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
0edf4568
Commit
0edf4568
authored
Feb 07, 2014
by
Robert Bradshaw
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' into 0.20.x
Conflicts: CHANGES.rst
parents
5e08f83c
e40d032f
Changes
47
Show whitespace changes
Inline
Side-by-side
Showing
47 changed files
with
1196 additions
and
441 deletions
+1196
-441
CHANGES.rst
CHANGES.rst
+6
-1
Cython/Build/Dependencies.py
Cython/Build/Dependencies.py
+9
-2
Cython/Build/Inline.py
Cython/Build/Inline.py
+3
-3
Cython/Compiler/Annotate.py
Cython/Compiler/Annotate.py
+11
-2
Cython/Compiler/Code.py
Cython/Compiler/Code.py
+10
-4
Cython/Compiler/Errors.py
Cython/Compiler/Errors.py
+1
-1
Cython/Compiler/ExprNodes.py
Cython/Compiler/ExprNodes.py
+36
-27
Cython/Compiler/FlowControl.py
Cython/Compiler/FlowControl.py
+12
-8
Cython/Compiler/Main.py
Cython/Compiler/Main.py
+8
-1
Cython/Compiler/ModuleNode.py
Cython/Compiler/ModuleNode.py
+66
-22
Cython/Compiler/Optimize.py
Cython/Compiler/Optimize.py
+7
-3
Cython/Compiler/ParseTreeTransforms.py
Cython/Compiler/ParseTreeTransforms.py
+2
-2
Cython/Compiler/Pipeline.py
Cython/Compiler/Pipeline.py
+1
-1
Cython/Compiler/Symtab.py
Cython/Compiler/Symtab.py
+1
-1
Cython/Compiler/Tests/TestParseTreeTransforms.py
Cython/Compiler/Tests/TestParseTreeTransforms.py
+5
-3
Cython/Compiler/TypeInference.py
Cython/Compiler/TypeInference.py
+7
-8
Cython/Debugger/Cygdb.py
Cython/Debugger/Cygdb.py
+33
-28
Cython/Debugger/Tests/TestLibCython.py
Cython/Debugger/Tests/TestLibCython.py
+57
-82
Cython/Includes/numpy/math.pxd
Cython/Includes/numpy/math.pxd
+86
-3
Cython/Shadow.py
Cython/Shadow.py
+1
-1
Cython/TestUtils.py
Cython/TestUtils.py
+27
-19
Cython/Tests/xmlrunner.py
Cython/Tests/xmlrunner.py
+6
-6
Cython/Utility/Buffer.c
Cython/Utility/Buffer.c
+5
-2
Cython/Utility/CythonFunction.c
Cython/Utility/CythonFunction.c
+1
-1
Cython/Utility/ModuleSetupCode.c
Cython/Utility/ModuleSetupCode.c
+11
-4
Cython/Utility/ObjectHandling.c
Cython/Utility/ObjectHandling.c
+40
-3
Cython/Utility/Printing.c
Cython/Utility/Printing.c
+10
-4
Cython/Utility/TypeConversion.c
Cython/Utility/TypeConversion.c
+2
-0
docs/src/reference/compilation.rst
docs/src/reference/compilation.rst
+3
-2
docs/src/tutorial/strings.rst
docs/src/tutorial/strings.rst
+143
-38
runtests.py
runtests.py
+69
-32
tests/build/common_include_dir.srctree
tests/build/common_include_dir.srctree
+1
-2
tests/memoryview/memoryview.pyx
tests/memoryview/memoryview.pyx
+6
-2
tests/memoryview/numpy_memoryview.pyx
tests/memoryview/numpy_memoryview.pyx
+1
-1
tests/run/builtin_min_max.pyx
tests/run/builtin_min_max.pyx
+34
-0
tests/run/bytearraymethods.pyx
tests/run/bytearraymethods.pyx
+1
-1
tests/run/cyfunction.pyx
tests/run/cyfunction.pyx
+63
-0
tests/run/embedsignatures.pyx
tests/run/embedsignatures.pyx
+2
-0
tests/run/include.pyx
tests/run/include.pyx
+5
-2
tests/run/includes/includefile.pxi
tests/run/includes/includefile.pxi
+3
-0
tests/run/inop.pyx
tests/run/inop.pyx
+5
-0
tests/run/py34_signature.pyx
tests/run/py34_signature.pyx
+91
-0
tests/run/type_inference.pyx
tests/run/type_inference.pyx
+24
-0
tests/run/type_inference_new.pyx
tests/run/type_inference_new.pyx
+31
-0
tests/run/uninitialized.py
tests/run/uninitialized.py
+48
-0
tests/run/withstat_py.py
tests/run/withstat_py.py
+32
-119
tests/run/withstat_py27.py
tests/run/withstat_py27.py
+170
-0
No files found.
CHANGES.rst
View file @
0edf4568
...
@@ -6,7 +6,6 @@ Cython Changelog
...
@@ -6,7 +6,6 @@ Cython Changelog
Latest
Latest
=======
=======
Features added
Features added
--------------
--------------
...
@@ -16,6 +15,12 @@ Bugs fixed
...
@@ -16,6 +15,12 @@ Bugs fixed
* List/Tuple literals multiplied by more than one factor were only multiplied
* List/Tuple literals multiplied by more than one factor were only multiplied
by the last factor instead of all.
by the last factor instead of all.
* Lookups of special methods (specifically for context managers) could fail
in Python <= 2.6/3.1.
* Local variables were erroneously appended to the signature introspection
of Cython implemented functions with keyword-only arguments under Python 3.
* In-place assignments to variables with inferred Python builtin/extension
* In-place assignments to variables with inferred Python builtin/extension
types could fail with type errors if the result value type was incompatible
types could fail with type errors if the result value type was incompatible
with the type of the previous value.
with the type of the previous value.
...
...
Cython/Build/Dependencies.py
View file @
0edf4568
...
@@ -91,7 +91,14 @@ def file_hash(filename):
...
@@ -91,7 +91,14 @@ def file_hash(filename):
path
=
os
.
path
.
normpath
(
filename
.
encode
(
"UTF-8"
))
path
=
os
.
path
.
normpath
(
filename
.
encode
(
"UTF-8"
))
m
=
hashlib
.
md5
(
str
(
len
(
path
))
+
":"
)
m
=
hashlib
.
md5
(
str
(
len
(
path
))
+
":"
)
m
.
update
(
path
)
m
.
update
(
path
)
m
.
update
(
open
(
filename
).
read
())
f
=
open
(
filename
,
'rb'
)
try
:
data
=
f
.
read
(
65000
)
while
data
:
m
.
update
(
data
)
data
=
f
.
read
(
65000
)
finally
:
f
.
close
()
return
m
.
hexdigest
()
return
m
.
hexdigest
()
def
parse_list
(
s
):
def
parse_list
(
s
):
...
@@ -671,7 +678,7 @@ def cythonize(module_list, exclude=[], nthreads=0, aliases=None, quiet=False, fo
...
@@ -671,7 +678,7 @@ def cythonize(module_list, exclude=[], nthreads=0, aliases=None, quiet=False, fo
options
[
'include_path'
]
=
[
'.'
]
options
[
'include_path'
]
=
[
'.'
]
if
'common_utility_include_dir'
in
options
:
if
'common_utility_include_dir'
in
options
:
if
options
.
get
(
'cache'
):
if
options
.
get
(
'cache'
):
raise
NotImplementedError
,
"common_utility_include_dir does not yet work with caching"
raise
NotImplementedError
(
"common_utility_include_dir does not yet work with caching"
)
if
not
os
.
path
.
exists
(
options
[
'common_utility_include_dir'
]):
if
not
os
.
path
.
exists
(
options
[
'common_utility_include_dir'
]):
os
.
makedirs
(
options
[
'common_utility_include_dir'
])
os
.
makedirs
(
options
[
'common_utility_include_dir'
])
c_options
=
CompilationOptions
(
**
options
)
c_options
=
CompilationOptions
(
**
options
)
...
...
Cython/Build/Inline.py
View file @
0edf4568
...
@@ -267,12 +267,12 @@ except ImportError:
...
@@ -267,12 +267,12 @@ except ImportError:
for
name
,
value
in
kwd_values
.
items
():
for
name
,
value
in
kwd_values
.
items
():
if
name
in
args
:
if
name
in
args
:
if
name
in
all
:
if
name
in
all
:
raise
TypeError
,
"Duplicate argument %s"
%
name
raise
TypeError
(
"Duplicate argument %s"
%
name
)
all
[
name
]
=
kwd_values
.
pop
(
name
)
all
[
name
]
=
kwd_values
.
pop
(
name
)
if
kwds
is
not
None
:
if
kwds
is
not
None
:
all
[
kwds
]
=
kwd_values
all
[
kwds
]
=
kwd_values
elif
kwd_values
:
elif
kwd_values
:
raise
TypeError
,
"Unexpected keyword arguments: %s"
%
kwd_values
.
keys
(
)
raise
TypeError
(
"Unexpected keyword arguments: %s"
%
kwd_values
.
keys
()
)
if
defaults
is
None
:
if
defaults
is
None
:
defaults
=
()
defaults
=
()
first_default
=
len
(
args
)
-
len
(
defaults
)
first_default
=
len
(
args
)
-
len
(
defaults
)
...
@@ -281,7 +281,7 @@ except ImportError:
...
@@ -281,7 +281,7 @@ except ImportError:
if
ix
>=
first_default
:
if
ix
>=
first_default
:
all
[
name
]
=
defaults
[
ix
-
first_default
]
all
[
name
]
=
defaults
[
ix
-
first_default
]
else
:
else
:
raise
TypeError
,
"Missing argument: %s"
%
name
raise
TypeError
(
"Missing argument: %s"
%
name
)
return
all
return
all
def
get_body
(
source
):
def
get_body
(
source
):
...
...
Cython/Compiler/Annotate.py
View file @
0edf4568
...
@@ -17,7 +17,6 @@ special_chars = [
...
@@ -17,7 +17,6 @@ special_chars = [
(
u'>'
,
u'
\
xF1
'
,
u'>'
),
(
u'>'
,
u'
\
xF1
'
,
u'>'
),
]
]
line_pos_comment
=
re
.
compile
(
r'/\
*.*?<<<<<<<<<<<<<<.*?
\*/\n*'
,
re
.
DOTALL
)
class
AnnotationCCodeWriter
(
CCodeWriter
):
class
AnnotationCCodeWriter
(
CCodeWriter
):
...
@@ -141,6 +140,7 @@ function toggleDiv(id) {
...
@@ -141,6 +140,7 @@ function toggleDiv(id) {
return
ur"<span class='%s'>%s</span>"
%
(
return
ur"<span class='%s'>%s</span>"
%
(
group_name
,
match
.
group
(
group_name
))
group_name
,
match
.
group
(
group_name
))
pos_comment_marker
=
u'/*
\
N{HORIZONTAL ELLIPSIS}
*/
\
n
'
k
=
0
k
=
0
code_source_file
=
self
.
code
.
get
(
source_filename
,
{})
code_source_file
=
self
.
code
.
get
(
source_filename
,
{})
for
line
in
lines
:
for
line
in
lines
:
...
@@ -150,6 +150,9 @@ function toggleDiv(id) {
...
@@ -150,6 +150,9 @@ function toggleDiv(id) {
except
KeyError
:
except
KeyError
:
code
=
''
code
=
''
else
:
else
:
code
=
_replace_pos_comment
(
pos_comment_marker
,
code
)
if
code
.
startswith
(
pos_comment_marker
):
code
=
code
[
len
(
pos_comment_marker
):]
code
=
html_escape
(
code
)
code
=
html_escape
(
code
)
calls
=
zero_calls
.
copy
()
calls
=
zero_calls
.
copy
()
...
@@ -165,7 +168,6 @@ function toggleDiv(id) {
...
@@ -165,7 +168,6 @@ function toggleDiv(id) {
f
.
write
(
line
.
rstrip
())
f
.
write
(
line
.
rstrip
())
f
.
write
(
u'</pre>
\
n
'
)
f
.
write
(
u'</pre>
\
n
'
)
code
=
re
.
sub
(
line_pos_comment
,
''
,
code
)
# inline annotations are redundant
f
.
write
(
u"<pre id='line%s' class='code' style='background-color: #%s'>%s</pre>"
%
(
k
,
color
,
code
))
f
.
write
(
u"<pre id='line%s' class='code' style='background-color: #%s'>%s</pre>"
%
(
k
,
color
,
code
))
f
.
write
(
u'</body></html>
\
n
'
)
f
.
write
(
u'</body></html>
\
n
'
)
f
.
close
()
f
.
close
()
...
@@ -183,6 +185,13 @@ _parse_code = re.compile(
...
@@ -183,6 +185,13 @@ _parse_code = re.compile(
).sub
).sub
_replace_pos_comment = re.compile(
# this matches what Cython generates as code line marker comment
ur'
^
\
s
*/
\
*
(
?
:(
?
:[
^*
]
|
\
*
[
^/
])
*
\
n
)
+
\
s
*
\
*/
\
s
*
\
n
',
re.M
).sub
class AnnotationItem(object):
class AnnotationItem(object):
def __init__(self, style, text, tag="", size=0):
def __init__(self, style, text, tag="", size=0):
...
...
Cython/Compiler/Code.py
View file @
0edf4568
...
@@ -249,7 +249,13 @@ class UtilityCodeBase(object):
...
@@ -249,7 +249,13 @@ class UtilityCodeBase(object):
continue
continue
# only pass lists when we have to: most argument expect one value or None
# only pass lists when we have to: most argument expect one value or None
if name == 'requires':
if name == 'requires':
values = [ cls.load(dep, from_file, **orig_kwargs) for dep in values ]
if orig_kwargs:
values = [cls.load(dep, from_file, **orig_kwargs)
for dep in sorted(values)]
else:
# dependencies are rarely unique, so use load_cached() when we can
values = [cls.load_cached(dep, from_file)
for dep in sorted(values)]
elif not values:
elif not values:
values = None
values = None
elif len(values) == 1:
elif len(values) == 1:
...
@@ -269,16 +275,16 @@ class UtilityCodeBase(object):
...
@@ -269,16 +275,16 @@ class UtilityCodeBase(object):
return cls(**kwargs)
return cls(**kwargs)
@classmethod
@classmethod
def load_cached(cls, utility_code_name, from_file=None, _cache={}):
def load_cached(cls, utility_code_name, from_file=None, _
_
cache={}):
"""
"""
Calls .load(), but using a per-type cache based on utility name and file name.
Calls .load(), but using a per-type cache based on utility name and file name.
"""
"""
key = (cls, from_file, utility_code_name)
key = (cls, from_file, utility_code_name)
try:
try:
return _cache[key]
return _
_
cache[key]
except KeyError:
except KeyError:
pass
pass
code = _cache[key] = cls.load(utility_code_name, from_file)
code = _
_
cache[key] = cls.load(utility_code_name, from_file)
return code
return code
@classmethod
@classmethod
...
...
Cython/Compiler/Errors.py
View file @
0edf4568
...
@@ -159,7 +159,7 @@ def report_error(err):
...
@@ -159,7 +159,7 @@ def report_error(err):
echo_file
.
write
(
line
.
encode
(
'ASCII'
,
'replace'
))
echo_file
.
write
(
line
.
encode
(
'ASCII'
,
'replace'
))
num_errors
=
num_errors
+
1
num_errors
=
num_errors
+
1
if
Options
.
fast_fail
:
if
Options
.
fast_fail
:
raise
AbortError
,
"fatal errors"
raise
AbortError
(
"fatal errors"
)
def
error
(
position
,
message
):
def
error
(
position
,
message
):
#print "Errors.error:", repr(position), repr(message) ###
#print "Errors.error:", repr(position), repr(message) ###
...
...
Cython/Compiler/ExprNodes.py
View file @
0edf4568
...
@@ -1690,7 +1690,7 @@ class NameNode(AtomicExprNode):
...
@@ -1690,7 +1690,7 @@ class NameNode(AtomicExprNode):
return
self
return
self
def
analyse_target_types
(
self
,
env
):
def
analyse_target_types
(
self
,
env
):
self
.
analyse_entry
(
env
)
self
.
analyse_entry
(
env
,
is_target
=
True
)
if
(
not
self
.
is_lvalue
()
and
self
.
entry
.
is_cfunction
and
if
(
not
self
.
is_lvalue
()
and
self
.
entry
.
is_cfunction
and
self
.
entry
.
fused_cfunction
and
self
.
entry
.
as_variable
):
self
.
entry
.
fused_cfunction
and
self
.
entry
.
as_variable
):
...
@@ -1750,12 +1750,12 @@ class NameNode(AtomicExprNode):
...
@@ -1750,12 +1750,12 @@ class NameNode(AtomicExprNode):
gil_message
=
"Accessing Python global or builtin"
gil_message
=
"Accessing Python global or builtin"
def
analyse_entry
(
self
,
env
):
def
analyse_entry
(
self
,
env
,
is_target
=
False
):
#print "NameNode.analyse_entry:", self.name ###
#print "NameNode.analyse_entry:", self.name ###
self
.
check_identifier_kind
()
self
.
check_identifier_kind
()
entry
=
self
.
entry
entry
=
self
.
entry
type
=
entry
.
type
type
=
entry
.
type
if
(
type
.
is_pyobject
and
self
.
inferred_type
and
if
(
not
is_target
and
type
.
is_pyobject
and
self
.
inferred_type
and
self
.
inferred_type
.
is_builtin_type
):
self
.
inferred_type
.
is_builtin_type
):
# assume that type inference is smarter than the static entry
# assume that type inference is smarter than the static entry
type
=
self
.
inferred_type
type
=
self
.
inferred_type
...
@@ -2536,7 +2536,9 @@ class WithExitCallNode(ExprNode):
...
@@ -2536,7 +2536,9 @@ class WithExitCallNode(ExprNode):
result_var
=
code
.
funcstate
.
allocate_temp
(
py_object_type
,
manage_ref
=
False
)
result_var
=
code
.
funcstate
.
allocate_temp
(
py_object_type
,
manage_ref
=
False
)
code
.
mark_pos
(
self
.
pos
)
code
.
mark_pos
(
self
.
pos
)
code
.
putln
(
"%s = PyObject_Call(%s, %s, NULL);"
%
(
code
.
globalstate
.
use_utility_code
(
UtilityCode
.
load_cached
(
"PyObjectCall"
,
"ObjectHandling.c"
))
code
.
putln
(
"%s = __Pyx_PyObject_Call(%s, %s, NULL);"
%
(
result_var
,
result_var
,
self
.
with_stat
.
exit_var
,
self
.
with_stat
.
exit_var
,
self
.
args
.
result
()))
self
.
args
.
result
()))
...
@@ -4657,8 +4659,10 @@ class SimpleCallNode(CallNode):
...
@@ -4657,8 +4659,10 @@ class SimpleCallNode(CallNode):
code
.
globalstate
.
use_utility_code
(
self
.
function
.
entry
.
utility_code
)
code
.
globalstate
.
use_utility_code
(
self
.
function
.
entry
.
utility_code
)
if
func_type
.
is_pyobject
:
if
func_type
.
is_pyobject
:
arg_code
=
self
.
arg_tuple
.
py_result
()
arg_code
=
self
.
arg_tuple
.
py_result
()
code
.
globalstate
.
use_utility_code
(
UtilityCode
.
load_cached
(
"PyObjectCall"
,
"ObjectHandling.c"
))
code
.
putln
(
code
.
putln
(
"%s = PyObject_Call(%s, %s, NULL); %s"
%
(
"%s =
__Pyx_
PyObject_Call(%s, %s, NULL); %s"
%
(
self
.
result
(),
self
.
result
(),
self
.
function
.
py_result
(),
self
.
function
.
py_result
(),
arg_code
,
arg_code
,
...
@@ -5087,8 +5091,10 @@ class GeneralCallNode(CallNode):
...
@@ -5087,8 +5091,10 @@ class GeneralCallNode(CallNode):
kwargs
=
self
.
keyword_args
.
py_result
()
kwargs
=
self
.
keyword_args
.
py_result
()
else
:
else
:
kwargs
=
'NULL'
kwargs
=
'NULL'
code
.
globalstate
.
use_utility_code
(
UtilityCode
.
load_cached
(
"PyObjectCall"
,
"ObjectHandling.c"
))
code
.
putln
(
code
.
putln
(
"%s = PyObject_Call(%s, %s, %s); %s"
%
(
"%s =
__Pyx_
PyObject_Call(%s, %s, %s); %s"
%
(
self
.
result
(),
self
.
result
(),
self
.
function
.
py_result
(),
self
.
function
.
py_result
(),
self
.
positional_args
.
py_result
(),
self
.
positional_args
.
py_result
(),
...
@@ -7604,18 +7610,14 @@ class CodeObjectNode(ExprNode):
...
@@ -7604,18 +7610,14 @@ class CodeObjectNode(ExprNode):
def
__init__
(
self
,
def_node
):
def
__init__
(
self
,
def_node
):
ExprNode
.
__init__
(
self
,
def_node
.
pos
,
def_node
=
def_node
)
ExprNode
.
__init__
(
self
,
def_node
.
pos
,
def_node
=
def_node
)
args
=
list
(
def_node
.
args
)
args
=
list
(
def_node
.
args
)
if
def_node
.
star_arg
:
# if we have args/kwargs, then the first two in var_entries are those
args
.
append
(
def_node
.
star_arg
)
local_vars
=
[
arg
for
arg
in
def_node
.
local_scope
.
var_entries
if
arg
.
name
]
if
def_node
.
starstar_arg
:
args
.
append
(
def_node
.
starstar_arg
)
local_vars
=
[
arg
for
arg
in
def_node
.
local_scope
.
var_entries
if
arg
.
name
]
self
.
varnames
=
TupleNode
(
self
.
varnames
=
TupleNode
(
def_node
.
pos
,
def_node
.
pos
,
args
=
[
IdentifierStringNode
(
arg
.
pos
,
value
=
arg
.
name
)
args
=
[
IdentifierStringNode
(
arg
.
pos
,
value
=
arg
.
name
)
for
arg
in
args
+
local_vars
],
for
arg
in
args
+
local_vars
],
is_temp
=
0
,
is_temp
=
0
,
is_literal
=
1
)
is_literal
=
1
)
def
may_be_none
(
self
):
def
may_be_none
(
self
):
return
False
return
False
...
@@ -7635,11 +7637,18 @@ class CodeObjectNode(ExprNode):
...
@@ -7635,11 +7637,18 @@ class CodeObjectNode(ExprNode):
file_path
=
StringEncoding
.
BytesLiteral
(
func
.
pos
[
0
].
get_filenametable_entry
().
encode
(
'utf8'
))
file_path
=
StringEncoding
.
BytesLiteral
(
func
.
pos
[
0
].
get_filenametable_entry
().
encode
(
'utf8'
))
file_path_const
=
code
.
get_py_string_const
(
file_path
,
identifier
=
False
,
is_str
=
True
)
file_path_const
=
code
.
get_py_string_const
(
file_path
,
identifier
=
False
,
is_str
=
True
)
code
.
putln
(
"%s = (PyObject*)__Pyx_PyCode_New(%d, %d, %d, 0, 0, %s, %s, %s, %s, %s, %s, %s, %s, %d, %s); %s"
%
(
flags
=
[]
if
self
.
def_node
.
star_arg
:
flags
.
append
(
'CO_VARARGS'
)
if
self
.
def_node
.
starstar_arg
:
flags
.
append
(
'CO_VARKEYWORDS'
)
code
.
putln
(
"%s = (PyObject*)__Pyx_PyCode_New(%d, %d, %d, 0, %s, %s, %s, %s, %s, %s, %s, %s, %s, %d, %s); %s"
%
(
self
.
result_code
,
self
.
result_code
,
len
(
func
.
args
)
,
# argcount
len
(
func
.
args
)
-
func
.
num_kwonly_args
,
# argcount
func
.
num_kwonly_args
,
# kwonlyargcount (Py3 only)
func
.
num_kwonly_args
,
# kwonlyargcount (Py3 only)
len
(
self
.
varnames
.
args
),
# nlocals
len
(
self
.
varnames
.
args
),
# nlocals
'|'
.
join
(
flags
)
or
'0'
,
# flags
Naming
.
empty_bytes
,
# code
Naming
.
empty_bytes
,
# code
Naming
.
empty_tuple
,
# consts
Naming
.
empty_tuple
,
# consts
Naming
.
empty_tuple
,
# names (FIXME)
Naming
.
empty_tuple
,
# names (FIXME)
...
@@ -7950,8 +7959,8 @@ class LocalsDictItemNode(DictItemNode):
...
@@ -7950,8 +7959,8 @@ class LocalsDictItemNode(DictItemNode):
class
FuncLocalsExprNode
(
DictNode
):
class
FuncLocalsExprNode
(
DictNode
):
def
__init__
(
self
,
pos
,
env
):
def
__init__
(
self
,
pos
,
env
):
local_vars
=
[
entry
.
name
for
entry
in
env
.
entries
.
values
()
local_vars
=
sorted
([
if
entry
.
name
]
entry
.
name
for
entry
in
env
.
entries
.
values
()
if
entry
.
name
])
items
=
[
LocalsDictItemNode
(
items
=
[
LocalsDictItemNode
(
pos
,
key
=
IdentifierStringNode
(
pos
,
value
=
var
),
pos
,
key
=
IdentifierStringNode
(
pos
,
value
=
var
),
value
=
NameNode
(
pos
,
name
=
var
,
allow_null
=
True
))
value
=
NameNode
(
pos
,
name
=
var
,
allow_null
=
True
))
...
@@ -8373,6 +8382,9 @@ class TypecastNode(ExprNode):
...
@@ -8373,6 +8382,9 @@ class TypecastNode(ExprNode):
"Cannot cast to a function type"
)
"Cannot cast to a function type"
)
self
.
type
=
PyrexTypes
.
error_type
self
.
type
=
PyrexTypes
.
error_type
self
.
operand
=
self
.
operand
.
analyse_types
(
env
)
self
.
operand
=
self
.
operand
.
analyse_types
(
env
)
if
self
.
type
is
PyrexTypes
.
c_bint_type
:
# short circuit this to a coercion
return
self
.
operand
.
coerce_to_boolean
(
env
)
to_py
=
self
.
type
.
is_pyobject
to_py
=
self
.
type
.
is_pyobject
from_py
=
self
.
operand
.
type
.
is_pyobject
from_py
=
self
.
operand
.
type
.
is_pyobject
if
from_py
and
not
to_py
and
self
.
operand
.
is_ephemeral
():
if
from_py
and
not
to_py
and
self
.
operand
.
is_ephemeral
():
...
@@ -8380,10 +8392,7 @@ class TypecastNode(ExprNode):
...
@@ -8380,10 +8392,7 @@ class TypecastNode(ExprNode):
error
(
self
.
pos
,
"Casting temporary Python object to non-numeric non-Python type"
)
error
(
self
.
pos
,
"Casting temporary Python object to non-numeric non-Python type"
)
if
to_py
and
not
from_py
:
if
to_py
and
not
from_py
:
if
self
.
type
is
bytes_type
and
self
.
operand
.
type
.
is_int
:
if
self
.
type
is
bytes_type
and
self
.
operand
.
type
.
is_int
:
# FIXME: the type cast node isn't needed in this case
return
CoerceIntToBytesNode
(
self
.
operand
,
env
)
# and can be dropped once analyse_types() can return a
# different node
self
.
operand
=
CoerceIntToBytesNode
(
self
.
operand
,
env
)
elif
self
.
operand
.
type
.
can_coerce_to_pyobject
(
env
):
elif
self
.
operand
.
type
.
can_coerce_to_pyobject
(
env
):
self
.
result_ctype
=
py_object_type
self
.
result_ctype
=
py_object_type
base_type
=
self
.
base_type
.
analyse
(
env
)
base_type
=
self
.
base_type
.
analyse
(
env
)
...
@@ -8405,7 +8414,7 @@ class TypecastNode(ExprNode):
...
@@ -8405,7 +8414,7 @@ class TypecastNode(ExprNode):
else
:
else
:
warning
(
self
.
pos
,
"No conversion from %s to %s, python object pointer used."
%
(
self
.
type
,
self
.
operand
.
type
))
warning
(
self
.
pos
,
"No conversion from %s to %s, python object pointer used."
%
(
self
.
type
,
self
.
operand
.
type
))
elif
from_py
and
to_py
:
elif
from_py
and
to_py
:
if
self
.
typecheck
and
self
.
type
.
is_pyobject
:
if
self
.
typecheck
:
self
.
operand
=
PyTypeTestNode
(
self
.
operand
,
self
.
type
,
env
,
notnone
=
True
)
self
.
operand
=
PyTypeTestNode
(
self
.
operand
,
self
.
type
,
env
,
notnone
=
True
)
elif
isinstance
(
self
.
operand
,
SliceIndexNode
):
elif
isinstance
(
self
.
operand
,
SliceIndexNode
):
# This cast can influence the created type of string slices.
# This cast can influence the created type of string slices.
...
@@ -9214,9 +9223,9 @@ class AddNode(NumBinopNode):
...
@@ -9214,9 +9223,9 @@ class AddNode(NumBinopNode):
if
type1
is
unicode_type
or
type2
is
unicode_type
:
if
type1
is
unicode_type
or
type2
is
unicode_type
:
if
type1
.
is_builtin_type
and
type2
.
is_builtin_type
:
if
type1
.
is_builtin_type
and
type2
.
is_builtin_type
:
if
self
.
operand1
.
may_be_none
()
or
self
.
operand2
.
may_be_none
():
if
self
.
operand1
.
may_be_none
()
or
self
.
operand2
.
may_be_none
():
return
'__Pyx_PyUnicode_Concat'
return
'__Pyx_PyUnicode_Concat
Safe
'
else
:
else
:
return
'PyUnicode_Concat'
return
'
__Pyx_
PyUnicode_Concat'
return
super
(
AddNode
,
self
).
py_operation_function
()
return
super
(
AddNode
,
self
).
py_operation_function
()
...
...
Cython/Compiler/FlowControl.py
View file @
0edf4568
...
@@ -193,9 +193,11 @@ class ControlFlow(object):
...
@@ -193,9 +193,11 @@ class ControlFlow(object):
def
mark_reference
(
self
,
node
,
entry
):
def
mark_reference
(
self
,
node
,
entry
):
if
self
.
block
and
self
.
is_tracked
(
entry
):
if
self
.
block
and
self
.
is_tracked
(
entry
):
self
.
block
.
stats
.
append
(
NameReference
(
node
,
entry
))
self
.
block
.
stats
.
append
(
NameReference
(
node
,
entry
))
# Local variable is definitely bound after this reference
## XXX: We don't track expression evaluation order so we can't use
if
not
node
.
allow_null
:
## XXX: successful reference as initialization sign.
self
.
block
.
bounded
.
add
(
entry
)
## # Local variable is definitely bound after this reference
## if not node.allow_null:
## self.block.bounded.add(entry)
self
.
entries
.
add
(
entry
)
self
.
entries
.
add
(
entry
)
def
normalize
(
self
):
def
normalize
(
self
):
...
@@ -548,9 +550,9 @@ def check_definitions(flow, compiler_directives):
...
@@ -548,9 +550,9 @@ def check_definitions(flow, compiler_directives):
references
[
stat
.
node
]
=
stat
.
entry
references
[
stat
.
node
]
=
stat
.
entry
stat
.
entry
.
cf_references
.
append
(
stat
)
stat
.
entry
.
cf_references
.
append
(
stat
)
stat
.
node
.
cf_state
.
update
(
state
)
stat
.
node
.
cf_state
.
update
(
state
)
if
not
stat
.
node
.
allow_null
:
##
if not stat.node.allow_null:
i_state
&=
~
i_assmts
.
bit
##
i_state &= ~i_assmts.bit
# after successful read, the state is known to be initialised
#
# #
after successful read, the state is known to be initialised
state
.
discard
(
Uninitialized
)
state
.
discard
(
Uninitialized
)
state
.
discard
(
Unknown
)
state
.
discard
(
Unknown
)
for
assmt
in
state
:
for
assmt
in
state
:
...
@@ -798,7 +800,7 @@ class ControlFlowAnalysis(CythonTransform):
...
@@ -798,7 +800,7 @@ class ControlFlowAnalysis(CythonTransform):
return
node
return
node
def
visit_AssignmentNode
(
self
,
node
):
def
visit_AssignmentNode
(
self
,
node
):
raise
InternalError
,
"Unhandled assignment node"
raise
InternalError
(
"Unhandled assignment node"
)
def
visit_SingleAssignmentNode
(
self
,
node
):
def
visit_SingleAssignmentNode
(
self
,
node
):
self
.
_visit
(
node
.
rhs
)
self
.
_visit
(
node
.
rhs
)
...
@@ -1097,7 +1099,7 @@ class ControlFlowAnalysis(CythonTransform):
...
@@ -1097,7 +1099,7 @@ class ControlFlowAnalysis(CythonTransform):
return
node
return
node
def
visit_LoopNode
(
self
,
node
):
def
visit_LoopNode
(
self
,
node
):
raise
InternalError
,
"Generic loops are not supported"
raise
InternalError
(
"Generic loops are not supported"
)
def
visit_WithTargetAssignmentStatNode
(
self
,
node
):
def
visit_WithTargetAssignmentStatNode
(
self
,
node
):
self
.
mark_assignment
(
node
.
lhs
,
node
.
rhs
)
self
.
mark_assignment
(
node
.
lhs
,
node
.
rhs
)
...
@@ -1121,6 +1123,7 @@ class ControlFlowAnalysis(CythonTransform):
...
@@ -1121,6 +1123,7 @@ class ControlFlowAnalysis(CythonTransform):
## XXX: links to exception handling point should be added by
## XXX: links to exception handling point should be added by
## XXX: children nodes
## XXX: children nodes
self
.
flow
.
block
.
add_child
(
entry_point
)
self
.
flow
.
block
.
add_child
(
entry_point
)
self
.
flow
.
nextblock
()
self
.
_visit
(
node
.
body
)
self
.
_visit
(
node
.
body
)
self
.
flow
.
exceptions
.
pop
()
self
.
flow
.
exceptions
.
pop
()
...
@@ -1181,6 +1184,7 @@ class ControlFlowAnalysis(CythonTransform):
...
@@ -1181,6 +1184,7 @@ class ControlFlowAnalysis(CythonTransform):
self
.
flow
.
block
=
body_block
self
.
flow
.
block
=
body_block
## XXX: Is it still required
## XXX: Is it still required
body_block
.
add_child
(
entry_point
)
body_block
.
add_child
(
entry_point
)
self
.
flow
.
nextblock
()
self
.
_visit
(
node
.
body
)
self
.
_visit
(
node
.
body
)
self
.
flow
.
exceptions
.
pop
()
self
.
flow
.
exceptions
.
pop
()
if
self
.
flow
.
loops
:
if
self
.
flow
.
loops
:
...
...
Cython/Compiler/Main.py
View file @
0edf4568
...
@@ -309,7 +309,14 @@ class Context(object):
...
@@ -309,7 +309,14 @@ class Context(object):
position
=
e
.
args
[
2
]
position
=
e
.
args
[
2
]
encoding
=
e
.
args
[
0
]
encoding
=
e
.
args
[
0
]
for
idx
,
c
in
enumerate
(
open
(
source_filename
,
"rb"
).
read
()):
f
=
open
(
source_filename
,
"rb"
)
try
:
byte_data
=
f
.
read
()
finally
:
f
.
close
()
# FIXME: make this at least a little less inefficient
for
idx
,
c
in
enumerate
(
byte_data
):
if
c
in
(
ord
(
'
\
n
'
),
'
\
n
'
):
if
c
in
(
ord
(
'
\
n
'
),
'
\
n
'
):
line
+=
1
line
+=
1
column
=
0
column
=
0
...
...
Cython/Compiler/ModuleNode.py
View file @
0edf4568
...
@@ -346,15 +346,44 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
...
@@ -346,15 +346,44 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
globalstate
.
finalize_main_c_code
()
globalstate
.
finalize_main_c_code
()
f
=
open_new_file
(
result
.
c_file
)
f
=
open_new_file
(
result
.
c_file
)
try
:
rootwriter
.
copyto
(
f
)
rootwriter
.
copyto
(
f
)
if
options
.
gdb_debug
:
finally
:
self
.
_serialize_lineno_map
(
env
,
rootwriter
)
f
.
close
()
f
.
close
()
result
.
c_file_generated
=
1
result
.
c_file_generated
=
1
if
options
.
gdb_debug
:
self
.
_serialize_lineno_map
(
env
,
rootwriter
)
if
Options
.
annotate
or
options
.
annotate
:
if
Options
.
annotate
or
options
.
annotate
:
self
.
_generate_annotations
(
rootwriter
,
result
)
def
_generate_annotations
(
self
,
rootwriter
,
result
):
self
.
annotate
(
rootwriter
)
self
.
annotate
(
rootwriter
)
rootwriter
.
save_annotation
(
result
.
main_source_file
,
result
.
c_file
)
rootwriter
.
save_annotation
(
result
.
main_source_file
,
result
.
c_file
)
# if we included files, additionally generate one annotation file for each
if
not
self
.
scope
.
included_files
:
return
search_include_file
=
self
.
scope
.
context
.
search_include_directories
target_dir
=
os
.
path
.
abspath
(
os
.
path
.
dirname
(
result
.
c_file
))
for
included_file
in
self
.
scope
.
included_files
:
target_file
=
os
.
path
.
abspath
(
os
.
path
.
join
(
target_dir
,
included_file
))
target_file_dir
=
os
.
path
.
dirname
(
target_file
)
if
not
target_file_dir
.
startswith
(
target_dir
):
# any other directories may not be writable => avoid trying
continue
source_file
=
search_include_file
(
included_file
,
""
,
self
.
pos
,
include
=
True
)
if
not
source_file
:
continue
if
target_file_dir
!=
target_dir
and
not
os
.
path
.
exists
(
target_file_dir
):
try
:
os
.
makedirs
(
target_file_dir
)
except
OSError
,
e
:
import
errno
if
e
.
errno
!=
errno
.
EEXIST
:
raise
rootwriter
.
save_annotation
(
source_file
,
target_file
)
def
_serialize_lineno_map
(
self
,
env
,
ccodewriter
):
def
_serialize_lineno_map
(
self
,
env
,
ccodewriter
):
tb
=
env
.
context
.
gdb_debug_outputwriter
tb
=
env
.
context
.
gdb_debug_outputwriter
markers
=
ccodewriter
.
buffer
.
allmarkers
()
markers
=
ccodewriter
.
buffer
.
allmarkers
()
...
@@ -382,13 +411,12 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
...
@@ -382,13 +411,12 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
self
.
find_referenced_modules
(
imported_module
,
module_list
,
modules_seen
)
self
.
find_referenced_modules
(
imported_module
,
module_list
,
modules_seen
)
module_list
.
append
(
env
)
module_list
.
append
(
env
)
def
sort_types_by_inheritance
(
self
,
type_dict
,
getkey
):
def
sort_types_by_inheritance
(
self
,
type_dict
,
type_order
,
getkey
):
# copy the types into a list moving each parent type before
# copy the types into a list moving each parent type before
# its first child
# its first child
type_items
=
type_dict
.
items
()
type_list
=
[]
type_list
=
[]
for
i
,
item
in
enumerate
(
type_items
):
for
i
,
key
in
enumerate
(
type_order
):
key
,
new_entry
=
item
new_entry
=
type_dict
[
key
]
# collect all base classes to check for children
# collect all base classes to check for children
hierarchy
=
set
()
hierarchy
=
set
()
...
@@ -413,43 +441,59 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
...
@@ -413,43 +441,59 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
return
type_list
return
type_list
def
sort_type_hierarchy
(
self
,
module_list
,
env
):
def
sort_type_hierarchy
(
self
,
module_list
,
env
):
vtab_dict
=
{}
# poor developer's OrderedDict
vtabslot_dict
=
{}
vtab_dict
,
vtab_dict_order
=
{},
[]
vtabslot_dict
,
vtabslot_dict_order
=
{},
[]
for
module
in
module_list
:
for
module
in
module_list
:
for
entry
in
module
.
c_class_entries
:
for
entry
in
module
.
c_class_entries
:
if
not
entry
.
in_cinclude
:
if
entry
.
used
and
not
entry
.
in_cinclude
:
type
=
entry
.
type
type
=
entry
.
type
if
type
.
vtabstruct_cname
:
key
=
type
.
vtabstruct_cname
vtab_dict
[
type
.
vtabstruct_cname
]
=
entry
if
not
key
:
continue
if
key
in
vtab_dict
:
# FIXME: this should *never* happen, but apparently it does
# for Cython generated utility code
from
Cython.Compiler.UtilityCode
import
NonManglingModuleScope
assert
isinstance
(
entry
.
scope
,
NonManglingModuleScope
),
str
(
entry
.
scope
)
assert
isinstance
(
vtab_dict
[
key
].
scope
,
NonManglingModuleScope
),
str
(
vtab_dict
[
key
].
scope
)
else
:
vtab_dict
[
key
]
=
entry
vtab_dict_order
.
append
(
key
)
all_defined_here
=
module
is
env
all_defined_here
=
module
is
env
for
entry
in
module
.
type_entries
:
for
entry
in
module
.
type_entries
:
if
all_defined_here
or
entry
.
defined_in_pxd
:
if
entry
.
used
and
(
all_defined_here
or
entry
.
defined_in_pxd
)
:
type
=
entry
.
type
type
=
entry
.
type
if
type
.
is_extension_type
and
not
entry
.
in_cinclude
:
if
type
.
is_extension_type
and
not
entry
.
in_cinclude
:
type
=
entry
.
type
type
=
entry
.
type
vtabslot_dict
[
type
.
objstruct_cname
]
=
entry
key
=
type
.
objstruct_cname
assert
key
not
in
vtabslot_dict
,
key
vtabslot_dict
[
key
]
=
entry
vtabslot_dict_order
.
append
(
key
)
def
vtabstruct_cname
(
entry_type
):
def
vtabstruct_cname
(
entry_type
):
return
entry_type
.
vtabstruct_cname
return
entry_type
.
vtabstruct_cname
vtab_list
=
self
.
sort_types_by_inheritance
(
vtab_list
=
self
.
sort_types_by_inheritance
(
vtab_dict
,
vtabstruct_cname
)
vtab_dict
,
vtab
_dict_order
,
vtab
struct_cname
)
def
objstruct_cname
(
entry_type
):
def
objstruct_cname
(
entry_type
):
return
entry_type
.
objstruct_cname
return
entry_type
.
objstruct_cname
vtabslot_list
=
self
.
sort_types_by_inheritance
(
vtabslot_list
=
self
.
sort_types_by_inheritance
(
vtabslot_dict
,
objstruct_cname
)
vtabslot_dict
,
vtabslot_dict_order
,
objstruct_cname
)
return
(
vtab_list
,
vtabslot_list
)
return
(
vtab_list
,
vtabslot_list
)
def
sort_cdef_classes
(
self
,
env
):
def
sort_cdef_classes
(
self
,
env
):
key_func
=
operator
.
attrgetter
(
'objstruct_cname'
)
key_func
=
operator
.
attrgetter
(
'objstruct_cname'
)
entry_dict
=
{}
entry_dict
,
entry_order
=
{},
[]
for
entry
in
env
.
c_class_entries
:
for
entry
in
env
.
c_class_entries
:
key
=
key_func
(
entry
.
type
)
key
=
key_func
(
entry
.
type
)
assert
key
not
in
entry_dict
assert
key
not
in
entry_dict
,
key
entry_dict
[
key
]
=
entry
entry_dict
[
key
]
=
entry
entry_order
.
append
(
key
)
env
.
c_class_entries
[:]
=
self
.
sort_types_by_inheritance
(
env
.
c_class_entries
[:]
=
self
.
sort_types_by_inheritance
(
entry_dict
,
key_func
)
entry_dict
,
entry_order
,
key_func
)
def
generate_type_definitions
(
self
,
env
,
modules
,
vtab_list
,
vtabslot_list
,
code
):
def
generate_type_definitions
(
self
,
env
,
modules
,
vtab_list
,
vtabslot_list
,
code
):
# TODO: Why are these separated out?
# TODO: Why are these separated out?
...
@@ -1892,7 +1936,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
...
@@ -1892,7 +1936,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
env
.
use_utility_code
(
streq_utility_code
)
env
.
use_utility_code
(
streq_utility_code
)
code
.
putln
()
code
.
putln
()
code
.
putln
(
"static char* %s_type_names[] = {"
%
Naming
.
import_star
)
code
.
putln
(
"static char* %s_type_names[] = {"
%
Naming
.
import_star
)
for
name
,
entry
in
env
.
entries
.
items
(
):
for
name
,
entry
in
sorted
(
env
.
entries
.
items
()
):
if
entry
.
is_type
:
if
entry
.
is_type
:
code
.
putln
(
'"%s",'
%
name
)
code
.
putln
(
'"%s",'
%
name
)
code
.
putln
(
"0"
)
code
.
putln
(
"0"
)
...
...
Cython/Compiler/Optimize.py
View file @
0edf4568
...
@@ -1554,6 +1554,9 @@ class EarlyReplaceBuiltinCalls(Visitor.EnvTransform):
...
@@ -1554,6 +1554,9 @@ class EarlyReplaceBuiltinCalls(Visitor.EnvTransform):
"""Replace min(a,b,...) and max(a,b,...) by explicit comparison code.
"""Replace min(a,b,...) and max(a,b,...) by explicit comparison code.
"""
"""
if
len
(
args
)
<=
1
:
if
len
(
args
)
<=
1
:
if
len
(
args
)
==
1
and
args
[
0
].
is_sequence_constructor
:
args
=
args
[
0
].
args
else
:
# leave this to Python
# leave this to Python
return
node
return
node
...
@@ -2187,6 +2190,7 @@ class OptimizeBuiltinCalls(Visitor.MethodDispatcherTransform):
...
@@ -2187,6 +2190,7 @@ class OptimizeBuiltinCalls(Visitor.MethodDispatcherTransform):
temp
=
None
temp
=
None
if
isinstance
(
types
,
ExprNodes
.
TupleNode
):
if
isinstance
(
types
,
ExprNodes
.
TupleNode
):
types
=
types
.
args
types
=
types
.
args
if
arg
.
is_attribute
or
not
arg
.
is_simple
():
arg
=
temp
=
UtilNodes
.
ResultRefNode
(
arg
)
arg
=
temp
=
UtilNodes
.
ResultRefNode
(
arg
)
elif
types
.
type
is
Builtin
.
type_type
:
elif
types
.
type
is
Builtin
.
type_type
:
types
=
[
types
]
types
=
[
types
]
...
...
Cython/Compiler/ParseTreeTransforms.py
View file @
0edf4568
...
@@ -1970,7 +1970,7 @@ class ExpandInplaceOperators(EnvTransform):
...
@@ -1970,7 +1970,7 @@ class ExpandInplaceOperators(EnvTransform):
return
node
,
[
node
]
return
node
,
[
node
]
elif
isinstance
(
node
,
ExprNodes
.
IndexNode
):
elif
isinstance
(
node
,
ExprNodes
.
IndexNode
):
if
node
.
is_buffer_access
:
if
node
.
is_buffer_access
:
raise
ValueError
,
"Buffer access"
raise
ValueError
(
"Buffer access"
)
base
,
temps
=
side_effect_free_reference
(
node
.
base
)
base
,
temps
=
side_effect_free_reference
(
node
.
base
)
index
=
LetRefNode
(
node
.
index
)
index
=
LetRefNode
(
node
.
index
)
return
ExprNodes
.
IndexNode
(
node
.
pos
,
base
=
base
,
index
=
index
),
temps
+
[
index
]
return
ExprNodes
.
IndexNode
(
node
.
pos
,
base
=
base
,
index
=
index
),
temps
+
[
index
]
...
@@ -2304,7 +2304,7 @@ class CreateClosureClasses(CythonTransform):
...
@@ -2304,7 +2304,7 @@ class CreateClosureClasses(CythonTransform):
if
not
from_closure
and
(
self
.
path
or
inner_node
):
if
not
from_closure
and
(
self
.
path
or
inner_node
):
if
not
inner_node
:
if
not
inner_node
:
if
not
node
.
py_cfunc_node
:
if
not
node
.
py_cfunc_node
:
raise
InternalError
,
"DefNode does not have assignment node"
raise
InternalError
(
"DefNode does not have assignment node"
)
inner_node
=
node
.
py_cfunc_node
inner_node
=
node
.
py_cfunc_node
inner_node
.
needs_self_code
=
False
inner_node
.
needs_self_code
=
False
node
.
needs_outer_scope
=
False
node
.
needs_outer_scope
=
False
...
...
Cython/Compiler/Pipeline.py
View file @
0edf4568
...
@@ -19,7 +19,7 @@ def dumptree(t):
...
@@ -19,7 +19,7 @@ def dumptree(t):
def
abort_on_errors
(
node
):
def
abort_on_errors
(
node
):
# Stop the pipeline if there are any errors.
# Stop the pipeline if there are any errors.
if
Errors
.
num_errors
!=
0
:
if
Errors
.
num_errors
!=
0
:
raise
AbortError
,
"pipeline break"
raise
AbortError
(
"pipeline break"
)
return
node
return
node
def
parse_stage_factory
(
context
):
def
parse_stage_factory
(
context
):
...
...
Cython/Compiler/Symtab.py
View file @
0edf4568
...
@@ -1542,7 +1542,7 @@ class LocalScope(Scope):
...
@@ -1542,7 +1542,7 @@ class LocalScope(Scope):
if
entry
is
not
None
:
if
entry
is
not
None
:
if
entry
.
scope
is
not
self
and
entry
.
scope
.
is_closure_scope
:
if
entry
.
scope
is
not
self
and
entry
.
scope
.
is_closure_scope
:
if
hasattr
(
entry
.
scope
,
"scope_class"
):
if
hasattr
(
entry
.
scope
,
"scope_class"
):
raise
InternalError
,
"lookup() after scope class created."
raise
InternalError
(
"lookup() after scope class created."
)
# The actual c fragment for the different scopes differs
# The actual c fragment for the different scopes differs
# on the outside and inside, so we make a new entry
# on the outside and inside, so we make a new entry
entry
.
in_closure
=
True
entry
.
in_closure
=
True
...
...
Cython/Compiler/Tests/TestParseTreeTransforms.py
View file @
0edf4568
...
@@ -271,13 +271,15 @@ class TestDebugTransform(DebuggerTestCase):
...
@@ -271,13 +271,15 @@ class TestDebugTransform(DebuggerTestCase):
assert
'puts'
in
spam_stepinto
assert
'puts'
in
spam_stepinto
assert
'some_c_function'
in
spam_stepinto
assert
'some_c_function'
in
spam_stepinto
except
:
except
:
print
open
(
self
.
debug_dest
).
read
()
f
=
open
(
self
.
debug_dest
)
try
:
print
(
f
.
read
())
finally
:
f
.
close
()
raise
raise
if
__name__
==
"__main__"
:
if
__name__
==
"__main__"
:
import
unittest
import
unittest
unittest
.
main
()
unittest
.
main
()
Cython/Compiler/TypeInference.py
View file @
0edf4568
...
@@ -383,6 +383,7 @@ class SimpleAssignmentTypeInferer(object):
...
@@ -383,6 +383,7 @@ class SimpleAssignmentTypeInferer(object):
if
not
types
:
if
not
types
:
node_type
=
py_object_type
node_type
=
py_object_type
else
:
else
:
entry
=
node
.
entry
node_type
=
spanning_type
(
node_type
=
spanning_type
(
types
,
entry
.
might_overflow
,
entry
.
pos
)
types
,
entry
.
might_overflow
,
entry
.
pos
)
node
.
inferred_type
=
node_type
node
.
inferred_type
=
node_type
...
@@ -392,6 +393,7 @@ class SimpleAssignmentTypeInferer(object):
...
@@ -392,6 +393,7 @@ class SimpleAssignmentTypeInferer(object):
if
assmt
.
inferred_type
is
not
None
]
if
assmt
.
inferred_type
is
not
None
]
if
not
types
:
if
not
types
:
return
return
entry
=
node
.
entry
return
spanning_type
(
types
,
entry
.
might_overflow
,
entry
.
pos
)
return
spanning_type
(
types
,
entry
.
might_overflow
,
entry
.
pos
)
def
resolve_assignments
(
assignments
):
def
resolve_assignments
(
assignments
):
...
@@ -404,10 +406,9 @@ class SimpleAssignmentTypeInferer(object):
...
@@ -404,10 +406,9 @@ class SimpleAssignmentTypeInferer(object):
infer_name_node_type
(
node
)
infer_name_node_type
(
node
)
# Resolve assmt
# Resolve assmt
inferred_type
=
assmt
.
infer_type
()
inferred_type
=
assmt
.
infer_type
()
done
=
False
assmts_resolved
.
add
(
assmt
)
assmts_resolved
.
add
(
assmt
)
resolved
.
add
(
assmt
)
resolved
.
add
(
assmt
)
assignments
-=
resolved
assignments
.
difference_update
(
resolved
)
return
resolved
return
resolved
def
partial_infer
(
assmt
):
def
partial_infer
(
assmt
):
...
@@ -427,10 +428,8 @@ class SimpleAssignmentTypeInferer(object):
...
@@ -427,10 +428,8 @@ class SimpleAssignmentTypeInferer(object):
# try to handle circular references
# try to handle circular references
partials
=
set
()
partials
=
set
()
for
assmt
in
assignments
:
for
assmt
in
assignments
:
partial_types
=
[]
if
assmt
in
partial_assmts
:
if
assmt
in
partial_assmts
:
continue
continue
for
node
in
assmt_to_names
[
assmt
]:
if
partial_infer
(
assmt
):
if
partial_infer
(
assmt
):
partials
.
add
(
assmt
)
partials
.
add
(
assmt
)
assmts_resolved
.
add
(
assmt
)
assmts_resolved
.
add
(
assmt
)
...
@@ -542,7 +541,7 @@ def safe_spanning_type(types, might_overflow, pos):
...
@@ -542,7 +541,7 @@ def safe_spanning_type(types, might_overflow, pos):
return
result_type
return
result_type
# TODO: double complex should be OK as well, but we need
# TODO: double complex should be OK as well, but we need
# to make sure everything is supported.
# to make sure everything is supported.
elif
result_type
.
is_int
and
not
might_overflow
:
elif
(
result_type
.
is_int
or
result_type
.
is_enum
)
and
not
might_overflow
:
return
result_type
return
result_type
return
py_object_type
return
py_object_type
...
...
Cython/Debugger/Cygdb.py
View file @
0edf4568
...
@@ -35,6 +35,7 @@ def make_command_file(path_to_debug_info, prefix_code='', no_import=False):
...
@@ -35,6 +35,7 @@ def make_command_file(path_to_debug_info, prefix_code='', no_import=False):
fd
,
tempfilename
=
tempfile
.
mkstemp
()
fd
,
tempfilename
=
tempfile
.
mkstemp
()
f
=
os
.
fdopen
(
fd
,
'w'
)
f
=
os
.
fdopen
(
fd
,
'w'
)
try
:
f
.
write
(
prefix_code
)
f
.
write
(
prefix_code
)
f
.
write
(
'set breakpoint pending on
\
n
'
)
f
.
write
(
'set breakpoint pending on
\
n
'
)
f
.
write
(
"set print pretty on
\
n
"
)
f
.
write
(
"set print pretty on
\
n
"
)
...
@@ -46,7 +47,11 @@ def make_command_file(path_to_debug_info, prefix_code='', no_import=False):
...
@@ -46,7 +47,11 @@ def make_command_file(path_to_debug_info, prefix_code='', no_import=False):
pass
pass
else
:
else
:
path
=
os
.
path
.
join
(
path_to_debug_info
,
"cython_debug"
,
"interpreter"
)
path
=
os
.
path
.
join
(
path_to_debug_info
,
"cython_debug"
,
"interpreter"
)
interpreter
=
open
(
path
).
read
()
interpreter_file
=
open
(
path
)
try
:
interpreter
=
interpreter_file
.
read
()
finally
:
interpreter_file
.
close
()
f
.
write
(
"file %s
\
n
"
%
interpreter
)
f
.
write
(
"file %s
\
n
"
%
interpreter
)
f
.
write
(
'
\
n
'
.
join
(
'cy import %s
\
n
'
%
fn
for
fn
in
debug_files
))
f
.
write
(
'
\
n
'
.
join
(
'cy import %s
\
n
'
%
fn
for
fn
in
debug_files
))
f
.
write
(
textwrap
.
dedent
(
'''
\
f
.
write
(
textwrap
.
dedent
(
'''
\
...
@@ -62,7 +67,7 @@ def make_command_file(path_to_debug_info, prefix_code='', no_import=False):
...
@@ -62,7 +67,7 @@ def make_command_file(path_to_debug_info, prefix_code='', no_import=False):
source .cygdbinit
source .cygdbinit
'''
))
'''
))
finally
:
f
.
close
()
f
.
close
()
return
tempfilename
return
tempfilename
...
...
Cython/Debugger/Tests/TestLibCython.py
View file @
0edf4568
...
@@ -35,7 +35,9 @@ build_ext = sys.modules['Cython.Distutils.build_ext']
...
@@ -35,7 +35,9 @@ build_ext = sys.modules['Cython.Distutils.build_ext']
have_gdb
=
None
have_gdb
=
None
def
test_gdb
():
def
test_gdb
():
global
have_gdb
global
have_gdb
if
have_gdb
is
None
:
if
have_gdb
is
not
None
:
return
have_gdb
try
:
try
:
p
=
subprocess
.
Popen
([
'gdb'
,
'-v'
],
stdout
=
subprocess
.
PIPE
)
p
=
subprocess
.
Popen
([
'gdb'
,
'-v'
],
stdout
=
subprocess
.
PIPE
)
have_gdb
=
True
have_gdb
=
True
...
@@ -43,7 +45,7 @@ def test_gdb():
...
@@ -43,7 +45,7 @@ def test_gdb():
# gdb was not installed
# gdb was not installed
have_gdb
=
False
have_gdb
=
False
else
:
else
:
gdb_version
=
p
.
stdout
.
read
().
decode
(
'ascii
'
)
gdb_version
=
p
.
stdout
.
read
().
decode
(
'ascii'
,
'ignore
'
)
p
.
wait
()
p
.
wait
()
p
.
stdout
.
close
()
p
.
stdout
.
close
()
...
@@ -54,17 +56,23 @@ def test_gdb():
...
@@ -54,17 +56,23 @@ def test_gdb():
if
gdb_version_number
>=
[
7
,
2
]:
if
gdb_version_number
>=
[
7
,
2
]:
python_version_script
=
tempfile
.
NamedTemporaryFile
(
mode
=
'w+'
)
python_version_script
=
tempfile
.
NamedTemporaryFile
(
mode
=
'w+'
)
try
:
python_version_script
.
write
(
python_version_script
.
write
(
'python import sys; print("%s %s" % sys.version_info[:2])'
)
'python import sys; print("%s %s" % sys.version_info[:2])'
)
python_version_script
.
flush
()
python_version_script
.
flush
()
p
=
subprocess
.
Popen
([
'gdb'
,
'-batch'
,
'-x'
,
python_version_script
.
name
],
p
=
subprocess
.
Popen
([
'gdb'
,
'-batch'
,
'-x'
,
python_version_script
.
name
],
stdout
=
subprocess
.
PIPE
)
stdout
=
subprocess
.
PIPE
)
try
:
python_version
=
p
.
stdout
.
read
().
decode
(
'ascii'
)
python_version
=
p
.
stdout
.
read
().
decode
(
'ascii'
)
p
.
wait
()
p
.
wait
()
finally
:
p
.
stdout
.
close
()
try
:
try
:
python_version_number
=
list
(
map
(
int
,
python_version
.
split
()))
python_version_number
=
list
(
map
(
int
,
python_version
.
split
()))
except
ValueError
:
except
ValueError
:
have_gdb
=
False
have_gdb
=
False
finally
:
python_version_script
.
close
()
# Be Python 3 compatible
# Be Python 3 compatible
if
(
not
have_gdb
if
(
not
have_gdb
...
@@ -146,6 +154,7 @@ class DebuggerTestCase(unittest.TestCase):
...
@@ -146,6 +154,7 @@ class DebuggerTestCase(unittest.TestCase):
finally
:
finally
:
optimization_disabler
.
restore_state
()
optimization_disabler
.
restore_state
()
sys
.
stderr
=
stderr
sys
.
stderr
=
stderr
new_stderr
.
close
()
# ext = Cython.Distutils.extension.Extension(
# ext = Cython.Distutils.extension.Extension(
# 'codefile',
# 'codefile',
...
@@ -227,45 +236,6 @@ class GdbDebuggerTestCase(DebuggerTestCase):
...
@@ -227,45 +236,6 @@ class GdbDebuggerTestCase(DebuggerTestCase):
os
.
path
.
abspath
(
Cython
.
__file__
))))
os
.
path
.
abspath
(
Cython
.
__file__
))))
env
=
dict
(
os
.
environ
,
PYTHONPATH
=
os
.
pathsep
.
join
(
paths
))
env
=
dict
(
os
.
environ
,
PYTHONPATH
=
os
.
pathsep
.
join
(
paths
))
try
:
p
=
subprocess
.
Popen
([
'gdb'
,
'-v'
],
stdout
=
subprocess
.
PIPE
)
have_gdb
=
True
except
OSError
:
# gdb was not installed
have_gdb
=
False
else
:
gdb_version
=
p
.
stdout
.
read
().
decode
(
'ascii'
)
p
.
wait
()
p
.
stdout
.
close
()
if
have_gdb
:
# Based on Lib/test/test_gdb.py
regex
=
"^GNU gdb [^
\
d]*(
\
d+)
\
.(
\
d+)"
gdb_version_number
=
list
(
map
(
int
,
re
.
search
(
regex
,
gdb_version
).
groups
()))
if
gdb_version_number
>=
[
7
,
2
]:
python_version_script
=
tempfile
.
NamedTemporaryFile
(
mode
=
'w+'
)
python_version_script
.
write
(
'python import sys; print("%s %s" % sys.version_info[:2])'
)
python_version_script
.
flush
()
p
=
subprocess
.
Popen
([
'gdb'
,
'-batch'
,
'-x'
,
python_version_script
.
name
],
stdout
=
subprocess
.
PIPE
)
python_version
=
p
.
stdout
.
read
().
decode
(
'ascii'
)
p
.
wait
()
try
:
python_version_number
=
list
(
map
(
int
,
python_version
.
split
()))
except
ValueError
:
have_gdb
=
False
# Be Python 3 compatible
if
(
not
have_gdb
or
gdb_version_number
<
[
7
,
2
]
or
python_version_number
<
[
2
,
6
]):
self
.
p
=
None
warnings
.
warn
(
'Skipping gdb tests, need gdb >= 7.2 with Python >= 2.6'
)
else
:
self
.
p
=
subprocess
.
Popen
(
self
.
p
=
subprocess
.
Popen
(
args
,
args
,
stdout
=
open
(
os
.
devnull
,
'w'
),
stdout
=
open
(
os
.
devnull
,
'w'
),
...
@@ -276,10 +246,15 @@ class GdbDebuggerTestCase(DebuggerTestCase):
...
@@ -276,10 +246,15 @@ class GdbDebuggerTestCase(DebuggerTestCase):
if
not
test_gdb
():
if
not
test_gdb
():
return
return
try
:
super
(
GdbDebuggerTestCase
,
self
).
tearDown
()
super
(
GdbDebuggerTestCase
,
self
).
tearDown
()
if
self
.
p
:
if
self
.
p
:
self
.
p
.
stderr
.
close
()
try
:
self
.
p
.
stdout
.
close
()
except
:
pass
try
:
self
.
p
.
stderr
.
close
()
except
:
pass
self
.
p
.
wait
()
self
.
p
.
wait
()
finally
:
os
.
remove
(
self
.
gdb_command_file
)
os
.
remove
(
self
.
gdb_command_file
)
...
@@ -292,15 +267,15 @@ class TestAll(GdbDebuggerTestCase):
...
@@ -292,15 +267,15 @@ class TestAll(GdbDebuggerTestCase):
out
,
err
=
self
.
p
.
communicate
()
out
,
err
=
self
.
p
.
communicate
()
err
=
err
.
decode
(
'UTF-8'
)
err
=
err
.
decode
(
'UTF-8'
)
exit_status
=
self
.
p
.
wait
()
exit_status
=
self
.
p
.
returncode
if
exit_status
==
1
:
if
exit_status
==
1
:
sys
.
stderr
.
write
(
err
)
sys
.
stderr
.
write
(
err
)
elif
exit_status
>=
2
:
elif
exit_status
>=
2
:
border
=
'*'
*
30
border
=
u
'*'
*
30
start
=
'%s v INSIDE GDB v %s'
%
(
border
,
border
)
start
=
u
'%s v INSIDE GDB v %s'
%
(
border
,
border
)
end
=
'%s ^ INSIDE GDB ^ %s'
%
(
border
,
border
)
end
=
u
'%s ^ INSIDE GDB ^ %s'
%
(
border
,
border
)
errmsg
=
'
\
n
%s
\
n
%s%s'
%
(
start
,
err
,
end
)
errmsg
=
u
'
\
n
%s
\
n
%s%s'
%
(
start
,
err
,
end
)
sys
.
stderr
.
write
(
errmsg
)
sys
.
stderr
.
write
(
errmsg
)
...
...
Cython/Includes/numpy/math.pxd
View file @
0edf4568
...
@@ -17,7 +17,7 @@
...
@@ -17,7 +17,7 @@
#
#
# Author: Lars Buitinck
# Author: Lars Buitinck
cdef
extern
from
"numpy/npy_math.h"
:
cdef
extern
from
"numpy/npy_math.h"
nogil
:
# Floating-point classification
# Floating-point classification
long
double
NAN
"NPY_NAN"
long
double
NAN
"NPY_NAN"
long
double
INFINITY
"NPY_INFINITY"
long
double
INFINITY
"NPY_INFINITY"
...
@@ -30,8 +30,6 @@ cdef extern from "numpy/npy_math.h":
...
@@ -30,8 +30,6 @@ cdef extern from "numpy/npy_math.h":
bint
isnan
"npy_isnan"
(
long
double
)
bint
isnan
"npy_isnan"
(
long
double
)
bint
signbit
"npy_signbit"
(
long
double
)
bint
signbit
"npy_signbit"
(
long
double
)
double
copysign
"npy_copysign"
(
double
,
double
)
# Math constants
# Math constants
long
double
E
"NPY_E"
long
double
E
"NPY_E"
long
double
LOG2E
"NPY_LOG2E"
# ln(e) / ln(2)
long
double
LOG2E
"NPY_LOG2E"
# ln(e) / ln(2)
...
@@ -46,5 +44,90 @@ cdef extern from "numpy/npy_math.h":
...
@@ -46,5 +44,90 @@ cdef extern from "numpy/npy_math.h":
long
double
EULER
"NPY_EULER"
# Euler constant (gamma, 0.57721)
long
double
EULER
"NPY_EULER"
# Euler constant (gamma, 0.57721)
# Low-level floating point manipulation (NumPy >=1.4)
# Low-level floating point manipulation (NumPy >=1.4)
float
copysignf
"npy_copysignf"
(
float
,
float
)
float
nextafterf
"npy_nextafterf"
(
float
x
,
float
y
)
float
spacingf
"npy_spacingf"
(
float
x
)
double
copysign
"npy_copysign"
(
double
,
double
)
double
nextafter
"npy_nextafter"
(
double
x
,
double
y
)
double
nextafter
"npy_nextafter"
(
double
x
,
double
y
)
double
spacing
"npy_spacing"
(
double
x
)
double
spacing
"npy_spacing"
(
double
x
)
long
double
copysignl
"npy_copysignl"
(
long
double
,
long
double
)
long
double
nextafterl
"npy_nextafterl"
(
long
double
x
,
long
double
y
)
long
double
spacingl
"npy_spacingl"
(
long
double
x
)
# Float C99 functions
float
sinf
"npy_sinf"
(
float
x
)
float
cosf
"npy_cosf"
(
float
x
)
float
tanf
"npy_tanf"
(
float
x
)
float
sinhf
"npy_sinhf"
(
float
x
)
float
coshf
"npy_coshf"
(
float
x
)
float
tanhf
"npy_tanhf"
(
float
x
)
float
fabsf
"npy_fabsf"
(
float
x
)
float
floorf
"npy_floorf"
(
float
x
)
float
ceilf
"npy_ceilf"
(
float
x
)
float
rintf
"npy_rintf"
(
float
x
)
float
sqrtf
"npy_sqrtf"
(
float
x
)
float
log10f
"npy_log10f"
(
float
x
)
float
logf
"npy_logf"
(
float
x
)
float
expf
"npy_expf"
(
float
x
)
float
expm1f
"npy_expm1f"
(
float
x
)
float
asinf
"npy_asinf"
(
float
x
)
float
acosf
"npy_acosf"
(
float
x
)
float
atanf
"npy_atanf"
(
float
x
)
float
asinhf
"npy_asinhf"
(
float
x
)
float
acoshf
"npy_acoshf"
(
float
x
)
float
atanhf
"npy_atanhf"
(
float
x
)
float
log1pf
"npy_log1pf"
(
float
x
)
float
exp2f
"npy_exp2f"
(
float
x
)
float
log2f
"npy_log2f"
(
float
x
)
float
atan2f
"npy_atan2f"
(
float
x
)
float
hypotf
"npy_hypotf"
(
float
x
)
float
powf
"npy_powf"
(
float
x
)
float
fmodf
"npy_fmodf"
(
float
x
)
float
modff
"npy_modff"
(
float
x
)
# Long double C99 functions
long
double
sinl
"npy_sinl"
(
long
double
x
)
long
double
cosl
"npy_cosl"
(
long
double
x
)
long
double
tanl
"npy_tanl"
(
long
double
x
)
long
double
sinhl
"npy_sinhl"
(
long
double
x
)
long
double
coshl
"npy_coshl"
(
long
double
x
)
long
double
tanhl
"npy_tanhl"
(
long
double
x
)
long
double
fabsl
"npy_fabsl"
(
long
double
x
)
long
double
floorl
"npy_floorl"
(
long
double
x
)
long
double
ceill
"npy_ceill"
(
long
double
x
)
long
double
rintl
"npy_rintl"
(
long
double
x
)
long
double
sqrtl
"npy_sqrtl"
(
long
double
x
)
long
double
log10l
"npy_log10l"
(
long
double
x
)
long
double
logl
"npy_logl"
(
long
double
x
)
long
double
expl
"npy_expl"
(
long
double
x
)
long
double
expm1l
"npy_expm1l"
(
long
double
x
)
long
double
asinl
"npy_asinl"
(
long
double
x
)
long
double
acosl
"npy_acosl"
(
long
double
x
)
long
double
atanl
"npy_atanl"
(
long
double
x
)
long
double
asinhl
"npy_asinhl"
(
long
double
x
)
long
double
acoshl
"npy_acoshl"
(
long
double
x
)
long
double
atanhl
"npy_atanhl"
(
long
double
x
)
long
double
log1pl
"npy_log1pl"
(
long
double
x
)
long
double
exp2l
"npy_exp2l"
(
long
double
x
)
long
double
log2l
"npy_log2l"
(
long
double
x
)
long
double
atan2l
"npy_atan2l"
(
long
double
x
)
long
double
hypotl
"npy_hypotl"
(
long
double
x
)
long
double
powl
"npy_powl"
(
long
double
x
)
long
double
fmodl
"npy_fmodl"
(
long
double
x
)
long
double
modfl
"npy_modfl"
(
long
double
x
)
# NumPy extensions
float
deg2radf
"npy_deg2radf"
(
float
x
)
float
rad2degf
"npy_rad2degf"
(
float
x
)
float
logaddexpf
"npy_logaddexpf"
(
float
x
)
float
logaddexp2f
"npy_logaddexp2f"
(
float
x
)
double
deg2rad
"npy_deg2rad"
(
double
x
)
double
rad2deg
"npy_rad2deg"
(
double
x
)
double
logaddexp
"npy_logaddexp"
(
double
x
)
double
logaddexp2
"npy_logaddexp2"
(
double
x
)
long
double
deg2radl
"npy_deg2radl"
(
long
double
x
)
long
double
rad2degl
"npy_rad2degl"
(
long
double
x
)
long
double
logaddexpl
"npy_logaddexpl"
(
long
double
x
)
long
double
logaddexp2l
"npy_logaddexp2l"
(
long
double
x
)
Cython/Shadow.py
View file @
0edf4568
# cython.* namespace for pure mode.
# cython.* namespace for pure mode.
__version__
=
"0.20"
__version__
=
"0.20
.post0
"
# BEGIN shameless copy from Cython/minivect/minitypes.py
# BEGIN shameless copy from Cython/minivect/minitypes.py
...
...
Cython/TestUtils.py
View file @
0edf4568
...
@@ -8,13 +8,15 @@ import unittest
...
@@ -8,13 +8,15 @@ import unittest
import
os
,
sys
import
os
,
sys
import
tempfile
import
tempfile
class
NodeTypeWriter
(
TreeVisitor
):
class
NodeTypeWriter
(
TreeVisitor
):
def
__init__
(
self
):
def
__init__
(
self
):
super
(
NodeTypeWriter
,
self
).
__init__
()
super
(
NodeTypeWriter
,
self
).
__init__
()
self
.
_indents
=
0
self
.
_indents
=
0
self
.
result
=
[]
self
.
result
=
[]
def
visit_Node
(
self
,
node
):
def
visit_Node
(
self
,
node
):
if
len
(
self
.
access_path
)
==
0
:
if
not
self
.
access_path
:
name
=
u"(root)"
name
=
u"(root)"
else
:
else
:
tip
=
self
.
access_path
[
-
1
]
tip
=
self
.
access_path
[
-
1
]
...
@@ -29,6 +31,7 @@ class NodeTypeWriter(TreeVisitor):
...
@@ -29,6 +31,7 @@ class NodeTypeWriter(TreeVisitor):
self
.
visitchildren
(
node
)
self
.
visitchildren
(
node
)
self
.
_indents
-=
1
self
.
_indents
-=
1
def
treetypes
(
root
):
def
treetypes
(
root
):
"""Returns a string representing the tree by class names.
"""Returns a string representing the tree by class names.
There's a leading and trailing whitespace so that it can be
There's a leading and trailing whitespace so that it can be
...
@@ -38,6 +41,7 @@ def treetypes(root):
...
@@ -38,6 +41,7 @@ def treetypes(root):
w
.
visit
(
root
)
w
.
visit
(
root
)
return
u"
\
n
"
.
join
([
u""
]
+
w
.
result
+
[
u""
])
return
u"
\
n
"
.
join
([
u""
]
+
w
.
result
+
[
u""
])
class
CythonTest
(
unittest
.
TestCase
):
class
CythonTest
(
unittest
.
TestCase
):
def
setUp
(
self
):
def
setUp
(
self
):
...
@@ -110,6 +114,7 @@ class CythonTest(unittest.TestCase):
...
@@ -110,6 +114,7 @@ class CythonTest(unittest.TestCase):
except
:
except
:
self
.
fail
(
str
(
sys
.
exc_info
()[
1
]))
self
.
fail
(
str
(
sys
.
exc_info
()[
1
]))
class
TransformTest
(
CythonTest
):
class
TransformTest
(
CythonTest
):
"""
"""
Utility base class for transform unit tests. It is based around constructing
Utility base class for transform unit tests. It is based around constructing
...
@@ -134,7 +139,6 @@ class TransformTest(CythonTest):
...
@@ -134,7 +139,6 @@ class TransformTest(CythonTest):
Plans: One could have a pxd dictionary parameter to run_pipeline.
Plans: One could have a pxd dictionary parameter to run_pipeline.
"""
"""
def
run_pipeline
(
self
,
pipeline
,
pyx
,
pxds
=
{}):
def
run_pipeline
(
self
,
pipeline
,
pyx
,
pxds
=
{}):
tree
=
self
.
fragment
(
pyx
,
pxds
).
root
tree
=
self
.
fragment
(
pyx
,
pxds
).
root
# Run pipeline
# Run pipeline
...
@@ -166,6 +170,7 @@ class TreeAssertVisitor(VisitorTransform):
...
@@ -166,6 +170,7 @@ class TreeAssertVisitor(VisitorTransform):
visit_Node
=
VisitorTransform
.
recurse_to_children
visit_Node
=
VisitorTransform
.
recurse_to_children
def
unpack_source_tree
(
tree_file
,
dir
=
None
):
def
unpack_source_tree
(
tree_file
,
dir
=
None
):
if
dir
is
None
:
if
dir
is
None
:
dir
=
tempfile
.
mkdtemp
()
dir
=
tempfile
.
mkdtemp
()
...
@@ -176,7 +181,8 @@ def unpack_source_tree(tree_file, dir=None):
...
@@ -176,7 +181,8 @@ def unpack_source_tree(tree_file, dir=None):
lines
=
f
.
readlines
()
lines
=
f
.
readlines
()
finally
:
finally
:
f
.
close
()
f
.
close
()
f
=
None
del
f
try
:
for
line
in
lines
:
for
line
in
lines
:
if
line
[:
5
]
==
'#####'
:
if
line
[:
5
]
==
'#####'
:
filename
=
line
.
strip
().
strip
(
'#'
).
strip
().
replace
(
'/'
,
os
.
path
.
sep
)
filename
=
line
.
strip
().
strip
(
'#'
).
strip
().
replace
(
'/'
,
os
.
path
.
sep
)
...
@@ -184,13 +190,15 @@ def unpack_source_tree(tree_file, dir=None):
...
@@ -184,13 +190,15 @@ def unpack_source_tree(tree_file, dir=None):
if
not
os
.
path
.
exists
(
os
.
path
.
dirname
(
path
)):
if
not
os
.
path
.
exists
(
os
.
path
.
dirname
(
path
)):
os
.
makedirs
(
os
.
path
.
dirname
(
path
))
os
.
makedirs
(
os
.
path
.
dirname
(
path
))
if
cur_file
is
not
None
:
if
cur_file
is
not
None
:
cur_file
.
close
()
f
,
cur_file
=
cur_file
,
None
f
.
close
()
cur_file
=
open
(
path
,
'w'
)
cur_file
=
open
(
path
,
'w'
)
elif
cur_file
is
not
None
:
elif
cur_file
is
not
None
:
cur_file
.
write
(
line
)
cur_file
.
write
(
line
)
elif
line
.
strip
()
and
not
line
.
lstrip
().
startswith
(
'#'
):
elif
line
.
strip
()
and
not
line
.
lstrip
().
startswith
(
'#'
):
if
line
.
strip
()
not
in
(
'"""'
,
"'''"
):
if
line
.
strip
()
not
in
(
'"""'
,
"'''"
):
header
.
append
(
line
)
header
.
append
(
line
)
finally
:
if
cur_file
is
not
None
:
if
cur_file
is
not
None
:
cur_file
.
close
()
cur_file
.
close
()
return
dir
,
''
.
join
(
header
)
return
dir
,
''
.
join
(
header
)
Cython/Tests/xmlrunner.py
View file @
0edf4568
...
@@ -222,14 +222,14 @@ class _XMLTestResult(_TextTestResult):
...
@@ -222,14 +222,14 @@ class _XMLTestResult(_TextTestResult):
testsuite
.
setAttribute
(
'name'
,
str
(
suite_name
))
testsuite
.
setAttribute
(
'name'
,
str
(
suite_name
))
testsuite
.
setAttribute
(
'tests'
,
str
(
len
(
tests
)))
testsuite
.
setAttribute
(
'tests'
,
str
(
len
(
tests
)))
testsuite
.
setAttribute
(
'time'
,
'%.3f'
%
\
testsuite
.
setAttribute
(
'time'
,
'%.3f'
%
sum
(
map
(
lambda
e
:
e
.
get_elapsed_time
(),
tests
)
))
sum
(
[
e
.
get_elapsed_time
()
for
e
in
tests
]
))
failures
=
filter
(
lambda
e
:
e
.
outcome
==
_TestInfo
.
FAILURE
,
tests
)
failures
=
len
([
1
for
e
in
tests
if
e
.
outcome
==
_TestInfo
.
FAILURE
]
)
testsuite
.
setAttribute
(
'failures'
,
str
(
len
(
failures
)
))
testsuite
.
setAttribute
(
'failures'
,
str
(
failures
))
errors
=
filter
(
lambda
e
:
e
.
outcome
==
_TestInfo
.
ERROR
,
tests
)
errors
=
len
([
1
for
e
in
tests
if
e
.
outcome
==
_TestInfo
.
ERROR
]
)
testsuite
.
setAttribute
(
'errors'
,
str
(
len
(
errors
)
))
testsuite
.
setAttribute
(
'errors'
,
str
(
errors
))
return
testsuite
return
testsuite
...
...
Cython/Utility/Buffer.c
View file @
0edf4568
...
@@ -593,8 +593,11 @@ __pyx_buffmt_parse_array(__Pyx_BufFmt_Context* ctx, const char** tsp)
...
@@ -593,8 +593,11 @@ __pyx_buffmt_parse_array(__Pyx_BufFmt_Context* ctx, const char** tsp)
/* Parse all numbers in the format string */
/* Parse all numbers in the format string */
while
(
*
ts
&&
*
ts
!=
')'
)
{
while
(
*
ts
&&
*
ts
!=
')'
)
{
if
(
isspace
(
*
ts
))
// ignore space characters (not using isspace() due to C/C++ problem on MacOS-X)
continue
;
switch
(
*
ts
)
{
case
' '
:
case
'\f'
:
case
'\r'
:
case
'\n'
:
case
'\t'
:
case
'\v'
:
continue
;
default:
break
;
/* not a 'break' in the loop */
}
number
=
__Pyx_BufFmt_ExpectNumber
(
&
ts
);
number
=
__Pyx_BufFmt_ExpectNumber
(
&
ts
);
if
(
number
==
-
1
)
return
NULL
;
if
(
number
==
-
1
)
return
NULL
;
...
...
Cython/Utility/CythonFunction.c
View file @
0edf4568
...
@@ -21,7 +21,6 @@
...
@@ -21,7 +21,6 @@
typedef
struct
{
typedef
struct
{
PyCFunctionObject
func
;
PyCFunctionObject
func
;
int
flags
;
PyObject
*
func_dict
;
PyObject
*
func_dict
;
PyObject
*
func_weakreflist
;
PyObject
*
func_weakreflist
;
PyObject
*
func_name
;
PyObject
*
func_name
;
...
@@ -35,6 +34,7 @@ typedef struct {
...
@@ -35,6 +34,7 @@ typedef struct {
/* Dynamic default args and annotations */
/* Dynamic default args and annotations */
void
*
defaults
;
void
*
defaults
;
int
defaults_pyobjects
;
int
defaults_pyobjects
;
int
flags
;
/* Defaults info */
/* Defaults info */
PyObject
*
defaults_tuple
;
/* Const defaults tuple */
PyObject
*
defaults_tuple
;
/* Const defaults tuple */
...
...
Cython/Utility/ModuleSetupCode.c
View file @
0edf4568
...
@@ -108,7 +108,7 @@
...
@@ -108,7 +108,7 @@
#if PY_MAJOR_VERSION < 3
#if PY_MAJOR_VERSION < 3
#define __Pyx_BUILTIN_MODULE_NAME "__builtin__"
#define __Pyx_BUILTIN_MODULE_NAME "__builtin__"
#define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) \
#define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) \
PyCode_New(a, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)
PyCode_New(a
+k
, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)
#define __Pyx_DefaultClassType PyClass_Type
#define __Pyx_DefaultClassType PyClass_Type
#else
#else
#define __Pyx_BUILTIN_MODULE_NAME "builtins"
#define __Pyx_BUILTIN_MODULE_NAME "builtins"
...
@@ -161,10 +161,17 @@
...
@@ -161,10 +161,17 @@
#define __Pyx_PyUnicode_READ(k, d, i) ((void)(k), (Py_UCS4)(((Py_UNICODE*)d)[i]))
#define __Pyx_PyUnicode_READ(k, d, i) ((void)(k), (Py_UCS4)(((Py_UNICODE*)d)[i]))
#endif
#endif
#if CYTHON_COMPILING_IN_PYPY
#define __Pyx_PyUnicode_Concat(a, b) PyNumber_Add(a, b)
#define __Pyx_PyUnicode_ConcatSafe(a, b) PyNumber_Add(a, b)
#else
#define __Pyx_PyUnicode_Concat(a, b) PyUnicode_Concat(a, b)
#define __Pyx_PyUnicode_ConcatSafe(a, b) ((unlikely((a) == Py_None) || unlikely((b) == Py_None)) ? \
PyNumber_Add(a, b) : __Pyx_PyUnicode_Concat(a, b))
#endif
#define __Pyx_PyString_FormatSafe(a, b) ((unlikely((a) == Py_None)) ? PyNumber_Remainder(a, b) : __Pyx_PyString_Format(a, b))
#define __Pyx_PyString_FormatSafe(a, b) ((unlikely((a) == Py_None)) ? PyNumber_Remainder(a, b) : __Pyx_PyString_Format(a, b))
#define __Pyx_PyUnicode_FormatSafe(a, b) ((unlikely((a) == Py_None)) ? PyNumber_Remainder(a, b) : PyUnicode_Format(a, b))
#define __Pyx_PyUnicode_FormatSafe(a, b) ((unlikely((a) == Py_None)) ? PyNumber_Remainder(a, b) : PyUnicode_Format(a, b))
#define __Pyx_PyUnicode_Concat(a, b) ((unlikely((a) == Py_None) || unlikely((b) == Py_None)) ? \
PyNumber_Add(a, b) : PyUnicode_Concat(a, b))
#if PY_MAJOR_VERSION >= 3
#if PY_MAJOR_VERSION >= 3
#define __Pyx_PyString_Format(a, b) PyUnicode_Format(a, b)
#define __Pyx_PyString_Format(a, b) PyUnicode_Format(a, b)
...
@@ -240,7 +247,7 @@
...
@@ -240,7 +247,7 @@
#define PyBoolObject PyLongObject
#define PyBoolObject PyLongObject
#endif
#endif
#if PY_VERSION_HEX < 0x030200
00
#if PY_VERSION_HEX < 0x030200
A4
typedef
long
Py_hash_t
;
typedef
long
Py_hash_t
;
#define __Pyx_PyInt_FromHash_t PyInt_FromLong
#define __Pyx_PyInt_FromHash_t PyInt_FromLong
#define __Pyx_PyInt_AsHash_t PyInt_AsLong
#define __Pyx_PyInt_AsHash_t PyInt_AsLong
...
...
Cython/Utility/ObjectHandling.c
View file @
0edf4568
...
@@ -1029,7 +1029,8 @@ static CYTHON_INLINE PyObject *__Pyx_GetAttr(PyObject *o, PyObject *n) {
...
@@ -1029,7 +1029,8 @@ static CYTHON_INLINE PyObject *__Pyx_GetAttr(PyObject *o, PyObject *n) {
/////////////// PyObjectLookupSpecial.proto ///////////////
/////////////// PyObjectLookupSpecial.proto ///////////////
//@requires: PyObjectGetAttrStr
//@requires: PyObjectGetAttrStr
#if CYTHON_COMPILING_IN_CPYTHON
#if CYTHON_COMPILING_IN_CPYTHON && (PY_VERSION_HEX >= 0x03020000 || PY_MAJOR_VERSION < 3 && PY_VERSION_HEX >= 0x02070000)
// looks like calling _PyType_Lookup() isn't safe in Py<=2.6/3.1
static
CYTHON_INLINE
PyObject
*
__Pyx_PyObject_LookupSpecial
(
PyObject
*
obj
,
PyObject
*
attr_name
)
{
static
CYTHON_INLINE
PyObject
*
__Pyx_PyObject_LookupSpecial
(
PyObject
*
obj
,
PyObject
*
attr_name
)
{
PyObject
*
res
;
PyObject
*
res
;
PyTypeObject
*
tp
=
Py_TYPE
(
obj
);
PyTypeObject
*
tp
=
Py_TYPE
(
obj
);
...
@@ -1052,7 +1053,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_LookupSpecial(PyObject* obj, PyObj
...
@@ -1052,7 +1053,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_LookupSpecial(PyObject* obj, PyObj
return
res
;
return
res
;
}
}
#else
#else
#define __Pyx_PyObject_LookupSpecial(o,n)
PyObject_GetAt
tr(o,n)
#define __Pyx_PyObject_LookupSpecial(o,n)
__Pyx_PyObject_GetAttrS
tr(o,n)
#endif
#endif
/////////////// PyObjectGetAttrStr.proto ///////////////
/////////////// PyObjectGetAttrStr.proto ///////////////
...
@@ -1093,6 +1094,7 @@ static CYTHON_INLINE int __Pyx_PyObject_SetAttrStr(PyObject* obj, PyObject* attr
...
@@ -1093,6 +1094,7 @@ static CYTHON_INLINE int __Pyx_PyObject_SetAttrStr(PyObject* obj, PyObject* attr
/////////////// PyObjectCallMethod.proto ///////////////
/////////////// PyObjectCallMethod.proto ///////////////
//@requires: PyObjectGetAttrStr
//@requires: PyObjectGetAttrStr
//@requires: PyObjectCall
//@substitute: naming
//@substitute: naming
static
PyObject
*
__Pyx_PyObject_CallMethodTuple
(
PyObject
*
obj
,
PyObject
*
method_name
,
PyObject
*
args
)
{
static
PyObject
*
__Pyx_PyObject_CallMethodTuple
(
PyObject
*
obj
,
PyObject
*
method_name
,
PyObject
*
args
)
{
...
@@ -1100,7 +1102,7 @@ static PyObject* __Pyx_PyObject_CallMethodTuple(PyObject* obj, PyObject* method_
...
@@ -1100,7 +1102,7 @@ static PyObject* __Pyx_PyObject_CallMethodTuple(PyObject* obj, PyObject* method_
if
(
unlikely
(
!
args
))
return
NULL
;
if
(
unlikely
(
!
args
))
return
NULL
;
method
=
__Pyx_PyObject_GetAttrStr
(
obj
,
method_name
);
method
=
__Pyx_PyObject_GetAttrStr
(
obj
,
method_name
);
if
(
unlikely
(
!
method
))
goto
bad
;
if
(
unlikely
(
!
method
))
goto
bad
;
result
=
PyObject_Call
(
method
,
args
,
NULL
);
result
=
__Pyx_
PyObject_Call
(
method
,
args
,
NULL
);
Py_DECREF
(
method
);
Py_DECREF
(
method
);
bad:
bad:
Py_DECREF
(
args
);
Py_DECREF
(
args
);
...
@@ -1123,3 +1125,38 @@ bad:
...
@@ -1123,3 +1125,38 @@ bad:
static
CYTHON_INLINE
PyObject
*
__Pyx_tp_new_kwargs
(
PyObject
*
type_obj
,
PyObject
*
args
,
PyObject
*
kwargs
)
{
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
));
return
(
PyObject
*
)
(((
PyTypeObject
*
)
type_obj
)
->
tp_new
((
PyTypeObject
*
)
type_obj
,
args
,
kwargs
));
}
}
/////////////// PyObjectCall.proto ///////////////
#if CYTHON_COMPILING_IN_CPYTHON
static
CYTHON_INLINE
PyObject
*
__Pyx_PyObject_Call
(
PyObject
*
func
,
PyObject
*
arg
,
PyObject
*
kw
);
/*proto*/
#else
#define __Pyx_PyObject_Call(func, arg, kw) PyObject_Call(func, arg, kw)
#endif
/////////////// PyObjectCall ///////////////
#if CYTHON_COMPILING_IN_CPYTHON
static
CYTHON_INLINE
PyObject
*
__Pyx_PyObject_Call
(
PyObject
*
func
,
PyObject
*
arg
,
PyObject
*
kw
)
{
PyObject
*
result
;
ternaryfunc
call
=
func
->
ob_type
->
tp_call
;
if
(
unlikely
(
!
call
))
return
PyObject_Call
(
func
,
arg
,
kw
);
#if PY_VERSION_HEX >= 0x02060000
if
(
unlikely
(
Py_EnterRecursiveCall
((
char
*
)
" while calling a Python object"
)))
return
NULL
;
#endif
result
=
(
*
call
)(
func
,
arg
,
kw
);
#if PY_VERSION_HEX >= 0x02060000
Py_LeaveRecursiveCall
();
#endif
if
(
unlikely
(
!
result
)
&&
unlikely
(
!
PyErr_Occurred
()))
{
PyErr_SetString
(
PyExc_SystemError
,
"NULL result without error in PyObject_Call"
);
}
return
result
;
}
#endif
Cython/Utility/Printing.c
View file @
0edf4568
...
@@ -47,10 +47,16 @@ static int __Pyx_Print(PyObject* f, PyObject *arg_tuple, int newline) {
...
@@ -47,10 +47,16 @@ static int __Pyx_Print(PyObject* f, PyObject *arg_tuple, int newline) {
if
(
PyString_Check
(
v
))
{
if
(
PyString_Check
(
v
))
{
char
*
s
=
PyString_AsString
(
v
);
char
*
s
=
PyString_AsString
(
v
);
Py_ssize_t
len
=
PyString_Size
(
v
);
Py_ssize_t
len
=
PyString_Size
(
v
);
if
(
len
>
0
&&
if
(
len
>
0
)
{
isspace
(
Py_CHARMASK
(
s
[
len
-
1
]))
&&
// append soft-space if necessary (not using isspace() due to C/C++ problem on MacOS-X)
s
[
len
-
1
]
!=
' '
)
switch
(
s
[
len
-
1
])
{
case
' '
:
break
;
case
'\f'
:
case
'\r'
:
case
'\n'
:
case
'\t'
:
case
'\v'
:
PyFile_SoftSpace
(
f
,
0
);
PyFile_SoftSpace
(
f
,
0
);
break
;
default:
break
;
}
}
}
}
}
}
if
(
newline
)
{
if
(
newline
)
{
...
...
Cython/Utility/TypeConversion.c
View file @
0edf4568
...
@@ -206,11 +206,13 @@ static CYTHON_INLINE char* __Pyx_PyObject_AsStringAndSize(PyObject* o, Py_ssize_
...
@@ -206,11 +206,13 @@ static CYTHON_INLINE char* __Pyx_PyObject_AsStringAndSize(PyObject* o, Py_ssize_
}
else
}
else
#endif
/* __PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT */
#endif
/* __PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT */
#if !CYTHON_COMPILING_IN_PYPY
#if PY_VERSION_HEX >= 0x02060000
#if PY_VERSION_HEX >= 0x02060000
if
(
PyByteArray_Check
(
o
))
{
if
(
PyByteArray_Check
(
o
))
{
*
length
=
PyByteArray_GET_SIZE
(
o
);
*
length
=
PyByteArray_GET_SIZE
(
o
);
return
PyByteArray_AS_STRING
(
o
);
return
PyByteArray_AS_STRING
(
o
);
}
else
}
else
#endif
#endif
#endif
{
{
char
*
result
;
char
*
result
;
...
...
docs/src/reference/compilation.rst
View file @
0edf4568
...
@@ -398,7 +398,7 @@ Globally
...
@@ -398,7 +398,7 @@ Globally
One can set compiler directives through a special header comment at the top of the file, like this::
One can set compiler directives through a special header comment at the top of the file, like this::
#!python
#!python
#cython: boundscheck=False
#cython:
language_level=3,
boundscheck=False
The comment must appear before any code (but can appear after other
The comment must appear before any code (but can appear after other
comments or whitespace).
comments or whitespace).
...
@@ -426,7 +426,8 @@ statement, like this::
...
@@ -426,7 +426,8 @@ statement, like this::
@cython.boundscheck(False) # turn off boundscheck for this function
@cython.boundscheck(False) # turn off boundscheck for this function
def f():
def f():
...
...
with cython.boundscheck(True): # turn it temporarily on again for this block
# turn it temporarily on again for this block
with cython.boundscheck(True):
...
...
.. Warning:: These two methods of setting directives are **not**
.. Warning:: These two methods of setting directives are **not**
...
...
docs/src/tutorial/strings.rst
View file @
0edf4568
...
@@ -16,46 +16,46 @@ implicitly insert these encoding/decoding steps.
...
@@ -16,46 +16,46 @@ implicitly insert these encoding/decoding steps.
Python string types in Cython code
Python string types in Cython code
----------------------------------
----------------------------------
Cython supports four Python string types:
``bytes``, ``str`
`,
Cython supports four Python string types:
:obj:`bytes`, :obj:`str
`,
``unicode`` and ``basestring``. The ``bytes`` and ``unicode`
` types
:obj:`unicode` and :obj:`basestring`. The :obj:`bytes` and :obj:`unicode
` types
are the specific types known from normal Python 2.x (named
``bytes`
`
are the specific types known from normal Python 2.x (named
:obj:`bytes
`
and
``str`
` in Python 3). Additionally, Cython also supports the
and
:obj:`str
` in Python 3). Additionally, Cython also supports the
``bytearray`
` type starting with Python 2.6. It behaves like the
:obj:`bytearray
` type starting with Python 2.6. It behaves like the
``bytes`
` type, except that it is mutable.
:obj:`bytes
` type, except that it is mutable.
The
``str`
` type is special in that it is the byte string in Python 2
The
:obj:`str
` type is special in that it is the byte string in Python 2
and the Unicode string in Python 3 (for Cython code compiled with
and the Unicode string in Python 3 (for Cython code compiled with
language level 2, i.e. the default). Meaning, it always corresponds
language level 2, i.e. the default). Meaning, it always corresponds
exactly with the type that the Python runtime itself calls
``str`
`.
exactly with the type that the Python runtime itself calls
:obj:`str
`.
Thus, in Python 2, both
``bytes`` and ``str`
` represent the byte string
Thus, in Python 2, both
:obj:`bytes` and :obj:`str
` represent the byte string
type, whereas in Python 3, both
``str`` and ``unicode`
` represent the
type, whereas in Python 3, both
:obj:`str` and :obj:`unicode
` represent the
Python Unicode string type. The switch is made at C compile time, the
Python Unicode string type. The switch is made at C compile time, the
Python version that is used to run Cython is not relevant.
Python version that is used to run Cython is not relevant.
When compiling Cython code with language level 3, the
``str`
` type is
When compiling Cython code with language level 3, the
:obj:`str
` type is
identified with exactly the Unicode string type at Cython compile time,
identified with exactly the Unicode string type at Cython compile time,
i.e. it does not identify with
``bytes`
` when running in Python 2.
i.e. it does not identify with
:obj:`bytes
` when running in Python 2.
Note that the
``str`` type is not compatible with the ``unicode`
`
Note that the
:obj:`str` type is not compatible with the :obj:`unicode
`
type in Python 2, i.e. you cannot assign a Unicode string to a variable
type in Python 2, i.e. you cannot assign a Unicode string to a variable
or argument that is typed
``str`
`. The attempt will result in either
or argument that is typed
:obj:`str
`. The attempt will result in either
a compile time error (if detectable) or a
``TypeError`
` exception at
a compile time error (if detectable) or a
:obj:`TypeError
` exception at
runtime. You should therefore be careful when you statically type a
runtime. You should therefore be careful when you statically type a
string variable in code that must be compatible with Python 2, as this
string variable in code that must be compatible with Python 2, as this
Python version allows a mix of byte strings and unicode strings for data
Python version allows a mix of byte strings and unicode strings for data
and users normally expect code to be able to work with both. Code that
and users normally expect code to be able to work with both. Code that
only targets Python 3 can safely type variables and arguments as either
only targets Python 3 can safely type variables and arguments as either
``bytes`` or ``unicode`
`.
:obj:`bytes` or :obj:`unicode
`.
The
``basestring`` type represents both the types ``str`` and ``unicode`
`,
The
:obj:`basestring` type represents both the types :obj:`str` and :obj:`unicode
`,
i.e. all Python text string types in Python 2 and Python 3. This can be
i.e. all Python text string types in Python 2 and Python 3. This can be
used for typing text variables that normally contain Unicode text (at
used for typing text variables that normally contain Unicode text (at
least in Python 3) but must additionally accept the
``str`
` type in
least in Python 3) but must additionally accept the
:obj:`str
` type in
Python 2 for backwards compatibility reasons. It is not compatible with
Python 2 for backwards compatibility reasons. It is not compatible with
the
``bytes`
` type. Its usage should be rare in normal Cython code as
the
:obj:`bytes
` type. Its usage should be rare in normal Cython code as
the generic
``object`
` type (i.e. untyped code) will normally be good
the generic
:obj:`object
` type (i.e. untyped code) will normally be good
enough and has the additional advantage of supporting the assignment of
enough and has the additional advantage of supporting the assignment of
string subtypes. Support for the
``basestring`
` type is new in Cython
string subtypes. Support for the
:obj:`basestring
` type is new in Cython
0.20.
0.20.
...
@@ -100,7 +100,7 @@ Python variable::
...
@@ -100,7 +100,7 @@ Python variable::
cdef char* c_string = c_call_returning_a_c_string()
cdef char* c_string = c_call_returning_a_c_string()
cdef bytes py_string = c_string
cdef bytes py_string = c_string
A type cast to
``object`` or ``bytes`
` will do the same thing::
A type cast to
:obj:`object` or :obj:`bytes
` will do the same thing::
py_string = <bytes> c_string
py_string = <bytes> c_string
...
@@ -163,13 +163,116 @@ however, when the C function stores the pointer for later use. Apart
...
@@ -163,13 +163,116 @@ however, when the C function stores the pointer for later use. Apart
from keeping a Python reference to the string object, no manual memory
from keeping a Python reference to the string object, no manual memory
management is required.
management is required.
Starting with Cython 0.20, the
``bytearray`
` type is supported and
Starting with Cython 0.20, the
:obj:`bytearray
` type is supported and
coerces in the same way as the
``bytes`
` type. However, when using it
coerces in the same way as the
:obj:`bytes
` type. However, when using it
in a C context, special care must be taken not to grow or shrink the
in a C context, special care must be taken not to grow or shrink the
object buffer after converting it to a C string pointer. These
object buffer after converting it to a C string pointer. These
modifications can change the internal buffer address, which will make
modifications can change the internal buffer address, which will make
the pointer invalid.
the pointer invalid.
Accepting strings from Python code
----------------------------------
The other side, receiving input from Python code, may appear simple
at first sight, as it only deals with objects. However, getting this
right without making the API too narrow or too unsafe may not be
entirely obvious.
In the case that the API only deals with byte strings, i.e. binary
data or encoded text, it is best not to type the input argument as
something like :obj:`bytes`, because that would restrict the allowed
input to exactly that type and exclude both subtypes and other kinds
of byte containers, e.g. :obj:`bytearray` objects or memory views.
Depending on how (and where) the data is being processed, it may be a
good idea to instead receive a 1-dimensional memory view, e.g.
::
def process_byte_data(unsigned char[:] data):
length = data.shape[0]
first_byte = data[0]
slice_view = data[1:-1]
...
Cython's memory views are described in more detail in
:doc:`../userguide/memoryviews`, but the above example already shows
most of the relevant functionality for 1-dimensional byte views. They
allow for efficient processing of arrays and accept anything that can
unpack itself into a byte buffer, without intermediate copying. The
processed content can finally be returned in the memory view itself
(or a slice of it), but it is often better to copy the data back into
a flat and simple :obj:`bytes` or :obj:`bytearray` object, especially
when only a small slice is returned. Since memoryviews do not copy the
data, they would otherwise keep the entire original buffer alive. The
general idea here is to be liberal with input by accepting any kind of
byte buffer, but strict with output by returning a simple, well adapted
object. This can simply be done as follows::
def process_byte_data(unsigned char[:] data):
# ... process the data
if return_all:
return bytes(data)
else:
# example for returning a slice
return bytes(data[5:35])
If the byte input is actually encoded text, and the further processing
should happen at the Unicode level, then the right thing to do is to
decode the input straight away. This is almost only a problem in Python
2.x, where Python code expects that it can pass a byte string (:obj:`str`)
with encoded text into a text API. Since this usually happens in more
than one place in the module's API, a helper function is almost always the
way to go, since it allows for easy adaptation of the input normalisation
process later.
This kind of input normalisation function will commonly look similar to
the following::
from cpython.version cimport PY_MAJOR_VERSION
cdef unicode _ustring(s):
if type(s) is unicode:
# fast path for most common case(s)
return <unicode>s
elif PY_MAJOR_VERSION < 3 and isinstance(s, bytes):
# only accept byte strings in Python 2.x, not in Py3
return (<bytes>s).decode('ascii')
elif isinstance(s, unicode):
# an evil cast to <unicode> might work here in some(!) cases,
# depending on what the further processing does. to be safe,
# we can always create a copy instead
return unicode(s)
else:
raise TypeError(...)
And should then be used like this::
def api_func(s):
text = _ustring(s)
...
Similarly, if the further processing happens at the byte level, but Unicode
string input should be accepted, then the following might work, if you are
using memory views::
# define a global name for whatever char type is used in the module
ctypedef unsigned char char_type
cdef char_type[:] _chars(s):
if isinstance(s, unicode):
# encode to the specific encoding used inside of the module
s = (<unicode>s).encode('utf8')
return s
In this case, you might want to additionally ensure that byte string
input really uses the correct encoding, e.g. if you require pure ASCII
input data, you can run over the buffer in a loop and check the highest
bit of each byte. This should then also be done in the input normalisation
function.
Dealing with "const"
Dealing with "const"
--------------------
--------------------
...
@@ -224,6 +327,7 @@ In Cython 0.18, these standard declarations have been changed to
...
@@ -224,6 +327,7 @@ In Cython 0.18, these standard declarations have been changed to
use the correct ``const`` modifier, so your code will automatically
use the correct ``const`` modifier, so your code will automatically
benefit from the new ``const`` support if it uses them.
benefit from the new ``const`` support if it uses them.
Decoding bytes to text
Decoding bytes to text
----------------------
----------------------
...
@@ -234,7 +338,7 @@ the C byte strings to Python Unicode strings on reception, and to
...
@@ -234,7 +338,7 @@ the C byte strings to Python Unicode strings on reception, and to
encode Python Unicode strings to C byte strings on the way out.
encode Python Unicode strings to C byte strings on the way out.
With a Python byte string object, you would normally just call the
With a Python byte string object, you would normally just call the
``.decode()`` method to decode it into a Unicode string::
``
bytes
.decode()`` method to decode it into a Unicode string::
ustring = byte_string.decode('UTF-8')
ustring = byte_string.decode('UTF-8')
...
@@ -318,6 +422,7 @@ assignment. Later access to the invalidated pointer will read invalid
...
@@ -318,6 +422,7 @@ assignment. Later access to the invalidated pointer will read invalid
memory and likely result in a segfault. Cython will therefore refuse
memory and likely result in a segfault. Cython will therefore refuse
to compile this code.
to compile this code.
C++ strings
C++ strings
-----------
-----------
...
@@ -375,7 +480,7 @@ There are two use cases where this is inconvenient. First, if all
...
@@ -375,7 +480,7 @@ There are two use cases where this is inconvenient. First, if all
C strings that are being processed (or the large majority) contain
C strings that are being processed (or the large majority) contain
text, automatic encoding and decoding from and to Python unicode
text, automatic encoding and decoding from and to Python unicode
objects can reduce the code overhead a little. In this case, you
objects can reduce the code overhead a little. In this case, you
can set the ``c_string_type`` directive in your module to
``unicode`
`
can set the ``c_string_type`` directive in your module to
:obj:`unicode
`
and the ``c_string_encoding`` to the encoding that your C code uses,
and the ``c_string_encoding`` to the encoding that your C code uses,
for example::
for example::
...
@@ -393,7 +498,7 @@ The second use case is when all C strings that are being processed
...
@@ -393,7 +498,7 @@ The second use case is when all C strings that are being processed
only contain ASCII encodable characters (e.g. numbers) and you want
only contain ASCII encodable characters (e.g. numbers) and you want
your code to use the native legacy string type in Python 2 for them,
your code to use the native legacy string type in Python 2 for them,
instead of always using Unicode. In this case, you can set the
instead of always using Unicode. In this case, you can set the
string type to
``str`
`::
string type to
:obj:`str
`::
# cython: c_string_type=str, c_string_encoding=ascii
# cython: c_string_type=str, c_string_encoding=ascii
...
@@ -472,15 +577,15 @@ whereas the following ``ISO-8859-15`` encoded source file will print
...
@@ -472,15 +577,15 @@ whereas the following ``ISO-8859-15`` encoded source file will print
Note that the unicode literal ``u'abcö'`` is a correctly decoded four
Note that the unicode literal ``u'abcö'`` is a correctly decoded four
character Unicode string in both cases, whereas the unprefixed Python
character Unicode string in both cases, whereas the unprefixed Python
``str`
` literal ``'abcö'`` will become a byte string in Python 2 (thus
:obj:`str
` literal ``'abcö'`` will become a byte string in Python 2 (thus
having length 4 or 5 in the examples above), and a 4 character Unicode
having length 4 or 5 in the examples above), and a 4 character Unicode
string in Python 3. If you are not familiar with encodings, this may
string in Python 3. If you are not familiar with encodings, this may
not appear obvious at first read. See `CEP 108`_ for details.
not appear obvious at first read. See `CEP 108`_ for details.
As a rule of thumb, it is best to avoid unprefixed non-ASCII
``str`
`
As a rule of thumb, it is best to avoid unprefixed non-ASCII
:obj:`str
`
literals and to use unicode string literals for all text. Cython also
literals and to use unicode string literals for all text. Cython also
supports the ``__future__`` import ``unicode_literals`` that instructs
supports the ``__future__`` import ``unicode_literals`` that instructs
the parser to read all unprefixed
``str`
` literals in a source file as
the parser to read all unprefixed
:obj:`str
` literals in a source file as
unicode string literals, just like Python 3.
unicode string literals, just like Python 3.
.. _`CEP 108`: http://wiki.cython.org/enhancements/stringliterals
.. _`CEP 108`: http://wiki.cython.org/enhancements/stringliterals
...
@@ -522,7 +627,7 @@ explicitly, and the following will print ``A`` (or ``b'A'`` in Python
...
@@ -522,7 +627,7 @@ explicitly, and the following will print ``A`` (or ``b'A'`` in Python
The explicit coercion works for any C integer type. Values outside of
The explicit coercion works for any C integer type. Values outside of
the range of a :c:type:`char` or :c:type:`unsigned char` will raise an
the range of a :c:type:`char` or :c:type:`unsigned char` will raise an
``OverflowError`
` at runtime. Coercion will also happen automatically
:obj:`OverflowError
` at runtime. Coercion will also happen automatically
when assigning to a typed variable, e.g.::
when assigning to a typed variable, e.g.::
cdef bytes py_byte_string
cdef bytes py_byte_string
...
@@ -544,10 +649,10 @@ The following will print 65::
...
@@ -544,10 +649,10 @@ The following will print 65::
cdef Py_UCS4 uchar_val = u'A'
cdef Py_UCS4 uchar_val = u'A'
print( <long>uchar_val )
print( <long>uchar_val )
Note that casting to a C
``long`` (or ``unsigned long`
`) will work
Note that casting to a C
:c:type:`long` (or :c:type:`unsigned long
`) will work
just fine, as the maximum code point value that a Unicode character
just fine, as the maximum code point value that a Unicode character
can have is 1114111 (``0x10FFFF``). On platforms with 32bit or more,
can have is 1114111 (``0x10FFFF``). On platforms with 32bit or more,
``int`
` is just as good.
:c:type:`int
` is just as good.
Narrow Unicode builds
Narrow Unicode builds
...
@@ -682,15 +787,15 @@ zero-terminated UTF-16 encoded :c:type:`wchar_t*` strings, so called
...
@@ -682,15 +787,15 @@ zero-terminated UTF-16 encoded :c:type:`wchar_t*` strings, so called
"wide strings".
"wide strings".
By default, Windows builds of CPython define :c:type:`Py_UNICODE` as
By default, Windows builds of CPython define :c:type:`Py_UNICODE` as
a synonym for :c:type:`wchar_t`. This makes internal
``unicode`
`
a synonym for :c:type:`wchar_t`. This makes internal
:obj:`unicode
`
representation compatible with UTF-16 and allows for efficient zero-copy
representation compatible with UTF-16 and allows for efficient zero-copy
conversions. This also means that Windows builds are always
conversions. This also means that Windows builds are always
`Narrow Unicode builds`_ with all the caveats.
`Narrow Unicode builds`_ with all the caveats.
To aid interoperation with Windows APIs, Cython 0.19 supports wide
To aid interoperation with Windows APIs, Cython 0.19 supports wide
strings (in the form of :c:type:`Py_UNICODE*`) and implicitly converts
strings (in the form of :c:type:`Py_UNICODE*`) and implicitly converts
them to and from
``unicode`
` string objects. These conversions behave the
them to and from
:obj:`unicode
` string objects. These conversions behave the
same way as they do for :c:type:`char*` and
``bytes`
` as described in
same way as they do for :c:type:`char*` and
:obj:`bytes
` as described in
`Passing byte strings`_.
`Passing byte strings`_.
In addition to automatic conversion, unicode literals that appear
In addition to automatic conversion, unicode literals that appear
...
@@ -722,7 +827,7 @@ Here is an example of how one would call a Unicode API on Windows::
...
@@ -722,7 +827,7 @@ Here is an example of how one would call a Unicode API on Windows::
APIs deprecated and inefficient.
APIs deprecated and inefficient.
One consequence of CPython 3.3 changes is that :py:func:`len` of
One consequence of CPython 3.3 changes is that :py:func:`len` of
``unicode`
` strings is always measured in *code points* ("characters"),
:obj:`unicode
` strings is always measured in *code points* ("characters"),
while Windows API expect the number of UTF-16 *code units*
while Windows API expect the number of UTF-16 *code units*
(where each surrogate is counted individually). To always get the number
(where each surrogate is counted individually). To always get the number
of code units, call :c:func:`PyUnicode_GetSize` directly.
of code units, call :c:func:`PyUnicode_GetSize` directly.
runtests.py
View file @
0edf4568
...
@@ -207,6 +207,11 @@ EXT_EXTRAS = {
...
@@ -207,6 +207,11 @@ EXT_EXTRAS = {
'tag:trace': update_linetrace_extension,
'tag:trace': update_linetrace_extension,
}
}
def _is_py3_before_32(excluded, version):
return version[0] >= 3 and version < (3,2)
# TODO: use tags
# TODO: use tags
VER_DEP_MODULES = {
VER_DEP_MODULES = {
# tests are excluded if 'CurrentPythonVersion OP VersionTuple', i.e.
# tests are excluded if 'CurrentPythonVersion OP VersionTuple', i.e.
...
@@ -248,10 +253,12 @@ VER_DEP_MODULES = {
...
@@ -248,10 +253,12 @@ VER_DEP_MODULES = {
'memoryview.numpy_memoryview',
'memoryview.numpy_memoryview',
'memoryview.memoryviewattrs',
'memoryview.memoryviewattrs',
'memoryview.memoryview',
'memoryview.memoryview',
'run.withstat_py',
]),
]),
(2,7) : (operator.lt, lambda x: x in ['run.withstat_py', # multi context with statement
(2,7) : (operator.lt, lambda x: x in ['run.withstat_py
27
', # multi context with statement
'run.yield_inside_lambda',
'run.yield_inside_lambda',
'run.test_dictviews',
'run.test_dictviews',
'run.pyclass_special_methods',
]),
]),
# The next line should start (3,); but this is a dictionary, so
# The next line should start (3,); but this is a dictionary, so
# we can only have one (3,) key. Since 2.7 is supposed to be the
# we can only have one (3,) key. Since 2.7 is supposed to be the
...
@@ -263,9 +270,14 @@ VER_DEP_MODULES = {
...
@@ -263,9 +270,14 @@ VER_DEP_MODULES = {
(3,): (operator.ge, lambda x: x in ['run.non_future_division',
(3,): (operator.ge, lambda x: x in ['run.non_future_division',
'compile.extsetslice',
'compile.extsetslice',
'compile.extdelslice',
'compile.extdelslice',
'run.special_methods_T561_py2']),
'run.special_methods_T561_py2'
]),
(3,1): (_is_py3_before_32, lambda x: x in ['run.pyclass_special_methods',
]),
(3,3) : (operator.lt, lambda x: x in ['build.package_compilation',
(3,3) : (operator.lt, lambda x: x in ['build.package_compilation',
]),
]),
(3,4,0,'beta',3) : (operator.le, lambda x: x in ['run.py34_signature',
]),
}
}
# files that should not be converted to Python 3 code with 2to3
# files that should not be converted to Python 3 code with 2to3
...
@@ -332,9 +344,18 @@ def parse_tags(filepath):
...
@@ -332,9 +344,18 @@ def parse_tags(filepath):
f.close()
f.close()
return tags
return tags
list_unchanging_dir = memoize(lambda x: os.listdir(x))
list_unchanging_dir = memoize(lambda x: os.listdir(x))
@memoize
def _list_pyregr_data_files(test_directory):
is_data_file = re.compile('(?:[.](txt|pem|db|html)|^bad.*[.]py)$').search
return ['__init__.py'] + [
filename for filename in list_unchanging_dir(test_directory)
if is_data_file(filename)]
def import_ext(module_name, file_path=None):
def import_ext(module_name, file_path=None):
if file_path:
if file_path:
import imp
import imp
...
@@ -514,18 +535,18 @@ class TestBuilder(object):
...
@@ -514,18 +535,18 @@ class TestBuilder(object):
elif 'no-cpp' in tags['tag'] and 'cpp' in self.languages:
elif 'no-cpp' in tags['tag'] and 'cpp' in self.languages:
languages = list(languages)
languages = list(languages)
languages.remove('cpp')
languages.remove('cpp')
tests = [ self.build_test(test_class, path, workdir, module,
tests = [ self.build_test(test_class, path, workdir, module,
tags,
language, expect_errors, warning_errors)
language, expect_errors, warning_errors)
for language in languages ]
for language in languages ]
return tests
return tests
def build_test(self, test_class, path, workdir, module,
def build_test(self, test_class, path, workdir, module,
tags,
language, expect_errors, warning_errors):
language, expect_errors, warning_errors):
language_workdir = os.path.join(workdir, language)
language_workdir = os.path.join(workdir, language)
if not os.path.exists(language_workdir):
if not os.path.exists(language_workdir):
os.makedirs(language_workdir)
os.makedirs(language_workdir)
workdir = os.path.join(language_workdir, module)
workdir = os.path.join(language_workdir, module)
return test_class(path, workdir, module,
return test_class(path, workdir, module,
tags,
language=language,
language=language,
expect_errors=expect_errors,
expect_errors=expect_errors,
annotate=self.annotate,
annotate=self.annotate,
...
@@ -538,11 +559,12 @@ class TestBuilder(object):
...
@@ -538,11 +559,12 @@ class TestBuilder(object):
warning_errors=warning_errors)
warning_errors=warning_errors)
class CythonCompileTestCase(unittest.TestCase):
class CythonCompileTestCase(unittest.TestCase):
def __init__(self, test_directory, workdir, module, language='c',
def __init__(self, test_directory, workdir, module,
tags,
language='c',
expect_errors=False, annotate=False, cleanup_workdir=True,
expect_errors=False, annotate=False, cleanup_workdir=True,
cleanup_sharedlibs=True, cleanup_failures=True, cython_only=False,
cleanup_sharedlibs=True, cleanup_failures=True, cython_only=False,
fork=True, language_level=2, warning_errors=False):
fork=True, language_level=2, warning_errors=False):
self.test_directory = test_directory
self.test_directory = test_directory
self.tags = tags
self.workdir = workdir
self.workdir = workdir
self.module = module
self.module = module
self.language = language
self.language = language
...
@@ -603,7 +625,7 @@ class CythonCompileTestCase(unittest.TestCase):
...
@@ -603,7 +625,7 @@ class CythonCompileTestCase(unittest.TestCase):
if not cleanup_c_files:
if not cleanup_c_files:
if (rmfile[-2:] in ("
.
c
", "
.
h
") or
if (rmfile[-2:] in ("
.
c
", "
.
h
") or
rmfile[-4:] == "
.
cpp
" or
rmfile[-4:] == "
.
cpp
" or
rmfile.endswith("
.
html
"
)):
rmfile.endswith("
.
html
") and rmfile.startswith(self.module
)):
continue
continue
if not cleanup_lib_files and (rmfile.endswith("
.
so
") or rmfile.endswith("
.
dll
")):
if not cleanup_lib_files and (rmfile.endswith("
.
so
") or rmfile.endswith("
.
dll
")):
continue
continue
...
@@ -641,9 +663,17 @@ class CythonCompileTestCase(unittest.TestCase):
...
@@ -641,9 +663,17 @@ class CythonCompileTestCase(unittest.TestCase):
if is_related(filename)]
if is_related(filename)]
def copy_files(self, test_directory, target_directory, file_list):
def copy_files(self, test_directory, target_directory, file_list):
# use symlink on Unix, copy on Windows
try:
copy = os.symlink
except AttributeError:
copy = shutil.copy
join = os.path.join
for filename in file_list:
for filename in file_list:
shutil.copy(os.path.join(test_directory, filename),
file_path = join(test_directory, filename)
target_directory)
if os.path.exists(file_path):
copy(file_path, join(target_directory, filename))
def source_files(self, workdir, module_name, file_list):
def source_files(self, workdir, module_name, file_list):
return ([self.build_target_filename(module_name)] +
return ([self.build_target_filename(module_name)] +
...
@@ -708,12 +738,6 @@ class CythonCompileTestCase(unittest.TestCase):
...
@@ -708,12 +738,6 @@ class CythonCompileTestCase(unittest.TestCase):
def run_distutils(self, test_directory, module, workdir, incdir,
def run_distutils(self, test_directory, module, workdir, incdir,
extra_extension_args=None):
extra_extension_args=None):
original_source = self.find_module_source_file(
os.path.join(test_directory, module + '.pyx'))
try:
tags = parse_tags(original_source)
except IOError:
tags = {}
cwd = os.getcwd()
cwd = os.getcwd()
os.chdir(workdir)
os.chdir(workdir)
try:
try:
...
@@ -748,12 +772,13 @@ class CythonCompileTestCase(unittest.TestCase):
...
@@ -748,12 +772,13 @@ class CythonCompileTestCase(unittest.TestCase):
# Set the language now as the fixer might need it
# Set the language now as the fixer might need it
extension.language = 'c++'
extension.language = 'c++'
for matcher, fixer in
EXT_EXTRAS.items(
):
for matcher, fixer in
list(EXT_EXTRAS.items()
):
if isinstance(matcher, str):
if isinstance(matcher, str):
# lazy init
del EXT_EXTRAS[matcher]
del EXT_EXTRAS[matcher]
matcher = string_selector(matcher)
matcher = string_selector(matcher)
EXT_EXTRAS[matcher] = fixer
EXT_EXTRAS[matcher] = fixer
if matcher(module, tags):
if matcher(module,
self.
tags):
newext = fixer(extension)
newext = fixer(extension)
if newext is EXCLUDE_EXT:
if newext is EXCLUDE_EXT:
return
return
...
@@ -891,9 +916,10 @@ def run_forked_test(result, run_func, test_name, fork=True):
...
@@ -891,9 +916,10 @@ def run_forked_test(result, run_func, test_name, fork=True):
child_id = os.fork()
child_id = os.fork()
if not child_id:
if not child_id:
result_code = 0
result_code = 0
output = None
try:
try:
try:
try:
tests = None
tests =
partial_result =
None
try:
try:
partial_result = PartialTestResult(result)
partial_result = PartialTestResult(result)
run_func(partial_result)
run_func(partial_result)
...
@@ -901,6 +927,8 @@ def run_forked_test(result, run_func, test_name, fork=True):
...
@@ -901,6 +927,8 @@ def run_forked_test(result, run_func, test_name, fork=True):
sys.stderr.flush()
sys.stderr.flush()
gc.collect()
gc.collect()
except Exception:
except Exception:
result_code = 1
if partial_result is not None:
if tests is None:
if tests is None:
# importing failed, try to fake a test class
# importing failed, try to fake a test class
tests = _FakeClass(
tests = _FakeClass(
...
@@ -908,14 +936,20 @@ def run_forked_test(result, run_func, test_name, fork=True):
...
@@ -908,14 +936,20 @@ def run_forked_test(result, run_func, test_name, fork=True):
_shortDescription=test_name,
_shortDescription=test_name,
module_name=None)
module_name=None)
partial_result.addError(tests, sys.exc_info())
partial_result.addError(tests, sys.exc_info())
result_code = 1
output = open(result_file, 'wb')
output = open(result_file, 'wb')
pickle.dump(partial_result.data(), output)
pickle.dump(partial_result.data(), output)
except:
except:
traceback.print_exc()
traceback.print_exc()
finally:
finally:
try:
output.close
()
try:
sys.stderr.flush
()
except: pass
except: pass
try: sys.stdout.flush()
except: pass
try:
if output is not None:
output.close()
except:
pass
os._exit(result_code)
os._exit(result_code)
try:
try:
...
@@ -1048,6 +1082,9 @@ class CythonPyregrTestCase(CythonRunTestCase):
...
@@ -1048,6 +1082,9 @@ class CythonPyregrTestCase(CythonRunTestCase):
set_initial_path="
SOURCEFILE
"))
set_initial_path="
SOURCEFILE
"))
patch_inspect_isfunction()
patch_inspect_isfunction()
def related_files(self, test_directory, module_name):
return _list_pyregr_data_files(test_directory)
def _run_unittest(self, result, *classes):
def _run_unittest(self, result, *classes):
"""Run tests from unittest.TestCase-derived classes."""
"""Run tests from unittest.TestCase-derived classes."""
valid_types = (unittest.TestSuite, unittest.TestCase)
valid_types = (unittest.TestSuite, unittest.TestCase)
...
@@ -1677,13 +1714,13 @@ def main():
...
@@ -1677,13 +1714,13 @@ def main():
_
,
return_code
=
runtests
(
options
,
cmd_args
,
coverage
)
_
,
return_code
=
runtests
(
options
,
cmd_args
,
coverage
)
print
(
"ALL DONE"
)
print
(
"ALL DONE"
)
try
:
try
:
check_thread_termination
(
ignore_seen
=
False
)
check_thread_termination
(
ignore_seen
=
False
)
sys
.
exit
(
return_code
)
except
PendingThreadsError
:
except
PendingThreadsError
:
# normal program exit won't kill the threads, do it the hard way here
# normal program exit won't kill the threads, do it the hard way here
flush_and_terminate
(
return_code
)
flush_and_terminate
(
return_code
)
else
:
sys
.
exit
(
return_code
)
def
runtests_callback
(
args
):
def
runtests_callback
(
args
):
...
...
tests/build/common_include_dir.srctree
View file @
0edf4568
...
@@ -61,11 +61,10 @@ import a, b, c
...
@@ -61,11 +61,10 @@ import a, b, c
######## fake_grep.py ########
######## fake_grep.py ########
import platform
import re
import re
import sys
import sys
if
platform == 'Windows
':
if
sys.platform == 'win32
':
opt, pattern, file = sys.argv[1:]
opt, pattern, file = sys.argv[1:]
assert opt == '-c'
assert opt == '-c'
count = 0
count = 0
...
...
tests/memoryview/memoryview.pyx
View file @
0edf4568
...
@@ -175,6 +175,7 @@ def test_cdef_attribute():
...
@@ -175,6 +175,7 @@ def test_cdef_attribute():
>>> test_cdef_attribute()
>>> test_cdef_attribute()
Memoryview is not initialized
Memoryview is not initialized
local variable 'myview' referenced before assignment
local variable 'myview' referenced before assignment
local variable 'myview' referenced before assignment
get_ext_obj called
get_ext_obj called
Memoryview is not initialized
Memoryview is not initialized
<MemoryView of 'array' object>
<MemoryView of 'array' object>
...
@@ -195,8 +196,11 @@ def test_cdef_attribute():
...
@@ -195,8 +196,11 @@ def test_cdef_attribute():
else
:
else
:
print
"No UnboundLocalError was raised"
print
"No UnboundLocalError was raised"
# uninitialized assignment is valid
cdef
int
[:]
otherview
cdef
int
[:]
otherview
=
myview
try
:
otherview
=
myview
except
UnboundLocalError
,
e
:
print
e
.
args
[
0
]
try
:
try
:
print
get_ext_obj
().
mview
print
get_ext_obj
().
mview
...
...
tests/memoryview/numpy_memoryview.pyx
View file @
0edf4568
...
@@ -406,7 +406,7 @@ cdef class DeallocateMe(object):
...
@@ -406,7 +406,7 @@ cdef class DeallocateMe(object):
# Disabled! References cycles don't seem to be supported by NumPy
# Disabled! References cycles don't seem to be supported by NumPy
# @testcase
# @testcase
def
acquire_release_cycle
(
obj
):
def
acquire_release_cycle
(
obj
):
"""
DISABLED_DOCSTRING
=
"""
>>> a = np.arange(20, dtype=np.object)
>>> a = np.arange(20, dtype=np.object)
>>> a[10] = DeallocateMe()
>>> a[10] = DeallocateMe()
>>> acquire_release_cycle(a)
>>> acquire_release_cycle(a)
...
...
tests/run/builtin_min_max.pyx
View file @
0edf4568
...
@@ -20,6 +20,40 @@ def min3(a,b,c):
...
@@ -20,6 +20,40 @@ def min3(a,b,c):
"""
"""
return
min
(
a
,
b
,
c
)
return
min
(
a
,
b
,
c
)
@
cython
.
test_assert_path_exists
(
"//CondExprNode"
)
@
cython
.
test_fail_if_path_exists
(
"//SimpleCallNode"
)
def
min3_list
(
a
,
b
,
c
):
"""
>>> min3_list(1,2,3)
1
>>> min3_list(2,3,1)
1
>>> min3_list(2,1,3)
1
>>> min3_list(3,1,2)
1
>>> min3_list(3,2,1)
1
"""
return
min
([
a
,
b
,
c
])
@
cython
.
test_assert_path_exists
(
"//CondExprNode"
)
@
cython
.
test_fail_if_path_exists
(
"//SimpleCallNode"
)
def
min3_tuple
(
a
,
b
,
c
):
"""
>>> min3_tuple(1,2,3)
1
>>> min3_tuple(2,3,1)
1
>>> min3_tuple(2,1,3)
1
>>> min3_tuple(3,1,2)
1
>>> min3_tuple(3,2,1)
1
"""
return
min
((
a
,
b
,
c
))
@
cython
.
test_assert_path_exists
(
"//CondExprNode"
)
@
cython
.
test_assert_path_exists
(
"//CondExprNode"
)
@
cython
.
test_fail_if_path_exists
(
"//SimpleCallNode"
)
@
cython
.
test_fail_if_path_exists
(
"//SimpleCallNode"
)
def
min3_typed
(
int
a
,
int
b
,
int
c
):
def
min3_typed
(
int
a
,
int
b
,
int
c
):
...
...
tests/run/bytearraymethods.pyx
View file @
0edf4568
...
@@ -199,7 +199,7 @@ def bytearray_decode_unbound_method(bytearray s, start=None, stop=None):
...
@@ -199,7 +199,7 @@ def bytearray_decode_unbound_method(bytearray s, start=None, stop=None):
return
bytearray
.
decode
(
s
[
start
:
stop
],
'utf8'
)
return
bytearray
.
decode
(
s
[
start
:
stop
],
'utf8'
)
def
bytearray_append
(
bytearray
b
,
char
c
,
int
i
,
object
o
):
def
bytearray_append
(
bytearray
b
,
signed
char
c
,
int
i
,
object
o
):
"""
"""
>>> b = bytearray(b'abc')
>>> b = bytearray(b'abc')
>>> b = bytearray_append(b, ord('x'), ord('y'), ord('z'))
>>> b = bytearray_append(b, ord('x'), ord('y'), ord('z'))
...
...
tests/run/cyfunction.pyx
View file @
0edf4568
...
@@ -4,6 +4,56 @@
...
@@ -4,6 +4,56 @@
import
sys
import
sys
IS_PY3
=
sys
.
version_info
[
0
]
>=
3
IS_PY3
=
sys
.
version_info
[
0
]
>=
3
IS_PY34
=
sys
.
version_info
>
(
3
,
4
,
0
,
'beta'
,
3
)
def
inspect_isroutine
():
"""
>>> inspect_isroutine()
True
"""
import
inspect
return
inspect
.
isroutine
(
inspect_isroutine
)
def
inspect_isfunction
():
"""
>>> inspect_isfunction()
False
False
"""
import
inspect
,
types
print
isinstance
(
inspect_isfunction
,
types
.
FunctionType
)
return
inspect
.
isfunction
(
inspect_isfunction
)
def
inspect_isbuiltin
():
"""
>>> inspect_isbuiltin()
False
False
"""
import
inspect
,
types
print
isinstance
(
inspect_isfunction
,
types
.
BuiltinFunctionType
)
return
inspect
.
isbuiltin
(
inspect_isbuiltin
)
def
inspect_signature
(
a
,
b
,
c
=
123
,
*
,
d
=
234
):
"""
>>> sig = inspect_signature(1, 2)
>>> if IS_PY34: list(sig.parameters)
... else: ['a', 'b', 'c', 'd']
['a', 'b', 'c', 'd']
>>> if IS_PY34: sig.parameters['c'].default == 123
... else: True
True
>>> if IS_PY34: sig.parameters['d'].default == 234
... else: True
True
"""
import
inspect
return
inspect
.
signature
(
inspect_signature
)
if
IS_PY34
else
None
def
test_dict
():
def
test_dict
():
"""
"""
...
@@ -42,6 +92,19 @@ def test_doc():
...
@@ -42,6 +92,19 @@ def test_doc():
'docstring'
'docstring'
"""
"""
def
test_hash
():
"""
>>> d = {test_hash: 123}
>>> test_hash in d
True
>>> d[test_hash]
123
>>> hash(test_hash) == hash(test_hash)
True
"""
def
test_closure
():
def
test_closure
():
"""
"""
>>> test_closure.func_closure is None
>>> test_closure.func_closure is None
...
...
tests/run/embedsignatures.pyx
View file @
0edf4568
...
@@ -4,6 +4,8 @@ import sys
...
@@ -4,6 +4,8 @@ import sys
if
sys
.
version_info
>=
(
3
,
4
):
if
sys
.
version_info
>=
(
3
,
4
):
def
funcdoc
(
f
):
def
funcdoc
(
f
):
if
not
f
.
__text_signature__
:
return
f
.
__doc__
doc
=
'%s%s'
%
(
f
.
__name__
,
f
.
__text_signature__
)
doc
=
'%s%s'
%
(
f
.
__name__
,
f
.
__text_signature__
)
if
f
.
__doc__
:
if
f
.
__doc__
:
if
'
\
n
'
in
f
.
__doc__
:
if
'
\
n
'
in
f
.
__doc__
:
...
...
tests/run/include.pyx
View file @
0edf4568
__doc__
=
u"""
__doc__
=
u"""
>>> D
>>> D
2
2
>>> XYZ
5
"""
"""
D
=
1
D
=
1
include
"testinclude.pxi"
include
"testinclude.pxi"
include
"includes/includefile.pxi"
tests/run/includes/includefile.pxi
0 → 100644
View file @
0edf4568
# this file will be included
XYZ
=
5
tests/run/inop.pyx
View file @
0edf4568
...
@@ -286,6 +286,11 @@ def conditional_none(int a):
...
@@ -286,6 +286,11 @@ def conditional_none(int a):
"""
"""
return
None
if
a
in
{
1
,
2
,
3
,
4
}
else
1
return
None
if
a
in
{
1
,
2
,
3
,
4
}
else
1
@
cython
.
test_assert_path_exists
(
"//BoolBinopNode"
,
"//BoolBinopNode//PrimaryCmpNode"
)
@
cython
.
test_fail_if_path_exists
(
"//ListNode"
)
def
n
(
a
):
def
n
(
a
):
"""
"""
>>> n('d *')
>>> n('d *')
...
...
tests/run/py34_signature.pyx
0 → 100644
View file @
0edf4568
# cython: binding=True, language_level=3
# mode: run
# tag: cyfunction
import
inspect
sig
=
inspect
.
Signature
.
from_function
def
signatures_match
(
f1
,
f2
):
if
sig
(
f1
)
==
sig
(
f2
):
return
None
# nothing to show in doctest
return
sig
(
f1
),
sig
(
f2
)
def
b
(
a
,
b
,
c
):
"""
>>> def py_b(a, b, c): pass
>>> signatures_match(b, py_b)
"""
def
c
(
a
,
b
,
c
=
1
):
"""
>>> def py_c(a, b, c=1): pass
>>> signatures_match(c, py_c)
"""
def
d
(
a
,
b
,
*
,
c
=
88
):
"""
>>> def py_d(a, b, *, c = 88): pass
>>> signatures_match(d, py_d)
"""
def
e
(
a
,
b
,
c
=
88
,
**
kwds
):
"""
>>> def py_e(a, b, c = 88, **kwds): pass
>>> signatures_match(e, py_e)
"""
def
f
(
a
,
b
,
*
,
c
,
d
=
42
):
"""
>>> def py_f(a, b, *, c, d = 42): pass
>>> signatures_match(f, py_f)
"""
def
g
(
a
,
b
,
*
,
c
,
d
=
42
,
e
=
17
,
f
,
**
kwds
):
"""
>>> def py_g(a, b, *, c, d = 42, e = 17, f, **kwds): pass
>>> signatures_match(g, py_g)
"""
def
h
(
a
,
b
,
*
args
,
c
,
d
=
42
,
e
=
17
,
f
,
**
kwds
):
"""
>>> def py_h(a, b, *args, c, d = 42, e = 17, f, **kwds): pass
>>> signatures_match(h, py_h)
"""
def
k
(
a
,
b
,
c
=
1
,
*
args
,
d
=
42
,
e
=
17
,
f
,
**
kwds
):
"""
>>> def py_k(a, b, c=1, *args, d = 42, e = 17, f, **kwds): pass
>>> signatures_match(k, py_k)
"""
def
l
(
*
,
a
,
b
,
c
=
88
):
"""
>>> def py_l(*, a, b, c = 88): pass
>>> signatures_match(l, py_l)
"""
def
m
(
a
,
*
,
b
,
c
=
88
):
"""
>>> def py_m(a, *, b, c = 88): pass
>>> signatures_match(m, py_m)
"""
a
,
b
,
c
=
b
,
c
,
a
def
n
(
a
,
*
,
b
,
c
=
88
):
"""
>>> def py_n(a, *, b, c = 88): pass
>>> signatures_match(n, py_n)
"""
tests/run/type_inference.pyx
View file @
0edf4568
...
@@ -647,3 +647,27 @@ def self_lookup(a):
...
@@ -647,3 +647,27 @@ def self_lookup(a):
def
bar
(
foo
):
def
bar
(
foo
):
qux
=
foo
qux
=
foo
quux
=
foo
[
qux
.
baz
]
quux
=
foo
[
qux
.
baz
]
cdef
enum
MyEnum
:
enum_x
=
1
enum_y
=
2
cdef
class
InferInProperties
:
"""
>>> InferInProperties().x
('double', 'unicode object', 'MyEnum', 'MyEnum')
"""
cdef
MyEnum
attr
def
__cinit__
(
self
):
self
.
attr
=
enum_x
property
x
:
def
__get__
(
self
):
a
=
1.0
b
=
u'abc'
c
=
self
.
attr
d
=
enum_y
c
=
d
return
typeof
(
a
),
typeof
(
b
),
typeof
(
c
),
typeof
(
d
)
tests/run/type_inference_new.pyx
View file @
0edf4568
...
@@ -26,6 +26,37 @@ def test_object_assmt():
...
@@ -26,6 +26,37 @@ def test_object_assmt():
assert
typeof
(
a
)
==
"Python object"
,
typeof
(
a
)
assert
typeof
(
a
)
==
"Python object"
,
typeof
(
a
)
assert
typeof
(
b
)
==
"long"
,
typeof
(
b
)
assert
typeof
(
b
)
==
"long"
,
typeof
(
b
)
class
RAdd
(
object
):
other
=
None
def
__radd__
(
self
,
other
):
self
.
_other
=
other
return
self
def
__repr__
(
self
):
return
'%s(%s)'
%
(
type
(
self
).
__name__
,
self
.
_other
)
def
test_inplace_assignment
():
"""
>>> test_inplace_assignment()
RAdd([1, 2, 3])
"""
l
=
[
1
,
2
,
3
]
# inferred type of l is list, but assignment result is object
l
+=
RAdd
()
return
l
def
test_reassignment
():
"""
>>> test_reassignment()
(1, 2, 3)
"""
l
=
[
1
,
2
,
3
]
l
=
(
1
,
2
,
3
)
return
l
def
test_long_vs_double
(
cond
):
def
test_long_vs_double
(
cond
):
"""
"""
>>> test_long_vs_double(0)
>>> test_long_vs_double(0)
...
...
tests/run/uninitialized.py
View file @
0edf4568
...
@@ -129,3 +129,51 @@ def test_class(cond):
...
@@ -129,3 +129,51 @@ def test_class(cond):
class
A
:
class
A
:
x
=
1
x
=
1
return
A
.
x
return
A
.
x
def
test_try_except_regression
(
c
):
"""
>>> test_try_except_regression(True)
(123,)
>>> test_try_except_regression(False)
Traceback (most recent call last):
...
UnboundLocalError: local variable 'a' referenced before assignment
"""
if
c
:
a
=
(
123
,)
try
:
return
a
except
:
return
a
def
test_try_finally_regression
(
c
):
"""
>>> test_try_finally_regression(True)
(123,)
>>> test_try_finally_regression(False)
Traceback (most recent call last):
...
UnboundLocalError: local variable 'a' referenced before assignment
"""
if
c
:
a
=
(
123
,)
try
:
return
a
finally
:
return
a
def
test_expression_calculation_order_bug
(
a
):
"""
>>> test_expression_calculation_order_bug(False)
[]
>>> test_expression_calculation_order_bug(True)
Traceback (most recent call last):
...
UnboundLocalError: local variable 'b' referenced before assignment
"""
if
not
a
:
b
=
[]
return
(
a
or
b
)
and
(
b
or
a
)
tests/run/withstat_py.py
View file @
0edf4568
import
sys
import
sys
def
typename
(
t
):
def
typename
(
t
):
name
=
type
(
t
).
__name__
name
=
type
(
t
).
__name__
if
sys
.
version_info
<
(
2
,
5
):
if
sys
.
version_info
<
(
2
,
5
):
...
@@ -9,9 +10,11 @@ def typename(t):
...
@@ -9,9 +10,11 @@ def typename(t):
name
=
'MyException'
name
=
'MyException'
return
"<type '%s'>"
%
name
return
"<type '%s'>"
%
name
class
MyException
(
Exception
):
class
MyException
(
Exception
):
pass
pass
class
ContextManager
(
object
):
class
ContextManager
(
object
):
def
__init__
(
self
,
value
,
exit_ret
=
None
):
def
__init__
(
self
,
value
,
exit_ret
=
None
):
self
.
value
=
value
self
.
value
=
value
...
@@ -25,6 +28,7 @@ class ContextManager(object):
...
@@ -25,6 +28,7 @@ class ContextManager(object):
print
(
"enter"
)
print
(
"enter"
)
return
self
.
value
return
self
.
value
def
no_as
():
def
no_as
():
"""
"""
>>> no_as()
>>> no_as()
...
@@ -35,6 +39,7 @@ def no_as():
...
@@ -35,6 +39,7 @@ def no_as():
with
ContextManager
(
"value"
):
with
ContextManager
(
"value"
):
print
(
"hello"
)
print
(
"hello"
)
def
basic
():
def
basic
():
"""
"""
>>> basic()
>>> basic()
...
@@ -45,6 +50,7 @@ def basic():
...
@@ -45,6 +50,7 @@ def basic():
with
ContextManager
(
"value"
)
as
x
:
with
ContextManager
(
"value"
)
as
x
:
print
(
x
)
print
(
x
)
def
with_pass
():
def
with_pass
():
"""
"""
>>> with_pass()
>>> with_pass()
...
@@ -54,6 +60,7 @@ def with_pass():
...
@@ -54,6 +60,7 @@ def with_pass():
with
ContextManager
(
"value"
)
as
x
:
with
ContextManager
(
"value"
)
as
x
:
pass
pass
def
with_return
():
def
with_return
():
"""
"""
>>> print(with_return())
>>> print(with_return())
...
@@ -64,6 +71,7 @@ def with_return():
...
@@ -64,6 +71,7 @@ def with_return():
with
ContextManager
(
"value"
)
as
x
:
with
ContextManager
(
"value"
)
as
x
:
return
x
return
x
def
with_break
():
def
with_break
():
"""
"""
>>> print(with_break())
>>> print(with_break())
...
@@ -77,6 +85,7 @@ def with_break():
...
@@ -77,6 +85,7 @@ def with_break():
print
(
"FAILED"
)
print
(
"FAILED"
)
return
c
return
c
def
with_continue
():
def
with_continue
():
"""
"""
>>> print(with_continue())
>>> print(with_continue())
...
@@ -94,6 +103,7 @@ def with_continue():
...
@@ -94,6 +103,7 @@ def with_continue():
print
(
"FAILED"
)
print
(
"FAILED"
)
return
c
return
c
def
with_exception
(
exit_ret
):
def
with_exception
(
exit_ret
):
"""
"""
>>> with_exception(None)
>>> with_exception(None)
...
@@ -113,6 +123,25 @@ def with_exception(exit_ret):
...
@@ -113,6 +123,25 @@ def with_exception(exit_ret):
except
:
except
:
print
(
"outer except"
)
print
(
"outer except"
)
def
with_real_lock
():
"""
>>> with_real_lock()
about to acquire lock
holding lock
lock no longer held
"""
from
threading
import
Lock
lock
=
Lock
()
print
(
"about to acquire lock"
)
with
lock
:
print
(
"holding lock"
)
print
(
"lock no longer held"
)
def
functions_in_with
():
def
functions_in_with
():
"""
"""
>>> f = functions_in_with()
>>> f = functions_in_with()
...
@@ -133,6 +162,7 @@ def functions_in_with():
...
@@ -133,6 +162,7 @@ def functions_in_with():
print
(
"outer except"
)
print
(
"outer except"
)
return
f
return
f
def
multitarget
():
def
multitarget
():
"""
"""
>>> multitarget()
>>> multitarget()
...
@@ -143,6 +173,7 @@ def multitarget():
...
@@ -143,6 +173,7 @@ def multitarget():
with
ContextManager
((
1
,
2
,
(
3
,
(
4
,
5
))))
as
(
a
,
b
,
(
c
,
(
d
,
e
))):
with
ContextManager
((
1
,
2
,
(
3
,
(
4
,
5
))))
as
(
a
,
b
,
(
c
,
(
d
,
e
))):
print
(
'%s %s %s %s %s'
%
(
a
,
b
,
c
,
d
,
e
))
print
(
'%s %s %s %s %s'
%
(
a
,
b
,
c
,
d
,
e
))
def
tupletarget
():
def
tupletarget
():
"""
"""
>>> tupletarget()
>>> tupletarget()
...
@@ -153,39 +184,12 @@ def tupletarget():
...
@@ -153,39 +184,12 @@ def tupletarget():
with
ContextManager
((
1
,
2
,
(
3
,
(
4
,
5
))))
as
t
:
with
ContextManager
((
1
,
2
,
(
3
,
(
4
,
5
))))
as
t
:
print
(
t
)
print
(
t
)
def
multimanager
():
"""
>>> multimanager()
enter
enter
enter
enter
enter
enter
2
value
1 2 3 4 5
nested
exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
"""
with
ContextManager
(
1
),
ContextManager
(
2
)
as
x
,
ContextManager
(
'value'
)
as
y
,
\
ContextManager
(
3
),
ContextManager
((
1
,
2
,
(
3
,
(
4
,
5
))))
as
(
a
,
b
,
(
c
,
(
d
,
e
))):
with
ContextManager
(
'nested'
)
as
nested
:
print
(
x
)
print
(
y
)
print
(
'%s %s %s %s %s'
%
(
a
,
b
,
c
,
d
,
e
))
print
(
nested
)
class
GetManager
(
object
):
class
GetManager
(
object
):
def
get
(
self
,
*
args
):
def
get
(
self
,
*
args
):
return
ContextManager
(
*
args
)
return
ContextManager
(
*
args
)
def
manager_from_expression
():
def
manager_from_expression
():
"""
"""
>>> manager_from_expression()
>>> manager_from_expression()
...
@@ -201,94 +205,3 @@ def manager_from_expression():
...
@@ -201,94 +205,3 @@ def manager_from_expression():
g
=
GetManager
()
g
=
GetManager
()
with
g
.
get
(
2
)
as
x
:
with
g
.
get
(
2
)
as
x
:
print
(
x
)
print
(
x
)
# Tests borrowed from pyregr test_with.py,
# modified to follow the constraints of Cython.
import
unittest
class
Dummy
(
object
):
def
__init__
(
self
,
value
=
None
,
gobble
=
False
):
if
value
is
None
:
value
=
self
self
.
value
=
value
self
.
gobble
=
gobble
self
.
enter_called
=
False
self
.
exit_called
=
False
def
__enter__
(
self
):
self
.
enter_called
=
True
return
self
.
value
def
__exit__
(
self
,
*
exc_info
):
self
.
exit_called
=
True
self
.
exc_info
=
exc_info
if
self
.
gobble
:
return
True
class
InitRaises
(
object
):
def
__init__
(
self
):
raise
RuntimeError
()
class
EnterRaises
(
object
):
def
__enter__
(
self
):
raise
RuntimeError
()
def
__exit__
(
self
,
*
exc_info
):
pass
class
ExitRaises
(
object
):
def
__enter__
(
self
):
pass
def
__exit__
(
self
,
*
exc_info
):
raise
RuntimeError
()
class
NestedWith
(
unittest
.
TestCase
):
"""
>>> NestedWith().runTest()
"""
def
runTest
(
self
):
self
.
testNoExceptions
()
self
.
testExceptionInExprList
()
self
.
testExceptionInEnter
()
self
.
testExceptionInExit
()
self
.
testEnterReturnsTuple
()
def
testNoExceptions
(
self
):
with
Dummy
()
as
a
,
Dummy
()
as
b
:
self
.
assertTrue
(
a
.
enter_called
)
self
.
assertTrue
(
b
.
enter_called
)
self
.
assertTrue
(
a
.
exit_called
)
self
.
assertTrue
(
b
.
exit_called
)
def
testExceptionInExprList
(
self
):
try
:
with
Dummy
()
as
a
,
InitRaises
():
pass
except
:
pass
self
.
assertTrue
(
a
.
enter_called
)
self
.
assertTrue
(
a
.
exit_called
)
def
testExceptionInEnter
(
self
):
try
:
with
Dummy
()
as
a
,
EnterRaises
():
self
.
fail
(
'body of bad with executed'
)
except
RuntimeError
:
pass
else
:
self
.
fail
(
'RuntimeError not reraised'
)
self
.
assertTrue
(
a
.
enter_called
)
self
.
assertTrue
(
a
.
exit_called
)
def
testExceptionInExit
(
self
):
body_executed
=
False
with
Dummy
(
gobble
=
True
)
as
a
,
ExitRaises
():
body_executed
=
True
self
.
assertTrue
(
a
.
enter_called
)
self
.
assertTrue
(
a
.
exit_called
)
self
.
assertTrue
(
body_executed
)
self
.
assertNotEqual
(
a
.
exc_info
[
0
],
None
)
def
testEnterReturnsTuple
(
self
):
with
Dummy
(
value
=
(
1
,
2
))
as
(
a1
,
a2
),
\
Dummy
(
value
=
(
10
,
20
))
as
(
b1
,
b2
):
self
.
assertEqual
(
1
,
a1
)
self
.
assertEqual
(
2
,
a2
)
self
.
assertEqual
(
10
,
b1
)
self
.
assertEqual
(
20
,
b2
)
tests/run/withstat_py27.py
0 → 100644
View file @
0edf4568
import
sys
def
typename
(
t
):
name
=
type
(
t
).
__name__
if
sys
.
version_info
<
(
2
,
5
):
if
name
==
'classobj'
and
issubclass
(
t
,
MyException
):
name
=
'type'
elif
name
==
'instance'
and
isinstance
(
t
,
MyException
):
name
=
'MyException'
return
"<type '%s'>"
%
name
class
MyException
(
Exception
):
pass
class
ContextManager
(
object
):
def
__init__
(
self
,
value
,
exit_ret
=
None
):
self
.
value
=
value
self
.
exit_ret
=
exit_ret
def
__exit__
(
self
,
a
,
b
,
tb
):
print
(
"exit %s %s %s"
%
(
typename
(
a
),
typename
(
b
),
typename
(
tb
)))
return
self
.
exit_ret
def
__enter__
(
self
):
print
(
"enter"
)
return
self
.
value
def
multimanager
():
"""
>>> multimanager()
enter
enter
enter
enter
enter
enter
2
value
1 2 3 4 5
nested
exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
"""
with
ContextManager
(
1
),
ContextManager
(
2
)
as
x
,
ContextManager
(
'value'
)
as
y
,
\
ContextManager
(
3
),
ContextManager
((
1
,
2
,
(
3
,
(
4
,
5
))))
as
(
a
,
b
,
(
c
,
(
d
,
e
))):
with
ContextManager
(
'nested'
)
as
nested
:
print
(
x
)
print
(
y
)
print
(
'%s %s %s %s %s'
%
(
a
,
b
,
c
,
d
,
e
))
print
(
nested
)
class
GetManager
(
object
):
def
get
(
self
,
*
args
):
return
ContextManager
(
*
args
)
def
manager_from_expression
():
"""
>>> manager_from_expression()
enter
1
exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
enter
2
exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
"""
with
GetManager
().
get
(
1
)
as
x
:
print
(
x
)
g
=
GetManager
()
with
g
.
get
(
2
)
as
x
:
print
(
x
)
# Tests borrowed from pyregr test_with.py,
# modified to follow the constraints of Cython.
import
unittest
class
Dummy
(
object
):
def
__init__
(
self
,
value
=
None
,
gobble
=
False
):
if
value
is
None
:
value
=
self
self
.
value
=
value
self
.
gobble
=
gobble
self
.
enter_called
=
False
self
.
exit_called
=
False
def
__enter__
(
self
):
self
.
enter_called
=
True
return
self
.
value
def
__exit__
(
self
,
*
exc_info
):
self
.
exit_called
=
True
self
.
exc_info
=
exc_info
if
self
.
gobble
:
return
True
class
InitRaises
(
object
):
def
__init__
(
self
):
raise
RuntimeError
()
class
EnterRaises
(
object
):
def
__enter__
(
self
):
raise
RuntimeError
()
def
__exit__
(
self
,
*
exc_info
):
pass
class
ExitRaises
(
object
):
def
__enter__
(
self
):
pass
def
__exit__
(
self
,
*
exc_info
):
raise
RuntimeError
()
class
NestedWith
(
unittest
.
TestCase
):
"""
>>> NestedWith().runTest()
"""
def
runTest
(
self
):
self
.
testNoExceptions
()
self
.
testExceptionInExprList
()
self
.
testExceptionInEnter
()
self
.
testExceptionInExit
()
self
.
testEnterReturnsTuple
()
def
testNoExceptions
(
self
):
with
Dummy
()
as
a
,
Dummy
()
as
b
:
self
.
assertTrue
(
a
.
enter_called
)
self
.
assertTrue
(
b
.
enter_called
)
self
.
assertTrue
(
a
.
exit_called
)
self
.
assertTrue
(
b
.
exit_called
)
def
testExceptionInExprList
(
self
):
try
:
with
Dummy
()
as
a
,
InitRaises
():
pass
except
:
pass
self
.
assertTrue
(
a
.
enter_called
)
self
.
assertTrue
(
a
.
exit_called
)
def
testExceptionInEnter
(
self
):
try
:
with
Dummy
()
as
a
,
EnterRaises
():
self
.
fail
(
'body of bad with executed'
)
except
RuntimeError
:
pass
else
:
self
.
fail
(
'RuntimeError not reraised'
)
self
.
assertTrue
(
a
.
enter_called
)
self
.
assertTrue
(
a
.
exit_called
)
def
testExceptionInExit
(
self
):
body_executed
=
False
with
Dummy
(
gobble
=
True
)
as
a
,
ExitRaises
():
body_executed
=
True
self
.
assertTrue
(
a
.
enter_called
)
self
.
assertTrue
(
a
.
exit_called
)
self
.
assertTrue
(
body_executed
)
self
.
assertNotEqual
(
a
.
exc_info
[
0
],
None
)
def
testEnterReturnsTuple
(
self
):
with
Dummy
(
value
=
(
1
,
2
))
as
(
a1
,
a2
),
\
Dummy
(
value
=
(
10
,
20
))
as
(
b1
,
b2
):
self
.
assertEqual
(
1
,
a1
)
self
.
assertEqual
(
2
,
a2
)
self
.
assertEqual
(
10
,
b1
)
self
.
assertEqual
(
20
,
b2
)
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