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
a8683244
Commit
a8683244
authored
May 15, 2015
by
Stefan Behnel
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
implement PEP 448 also for list/tuple literals
parent
0e6a7b7d
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
540 additions
and
104 deletions
+540
-104
CHANGES.rst
CHANGES.rst
+1
-2
Cython/Compiler/ExprNodes.py
Cython/Compiler/ExprNodes.py
+143
-32
Cython/Compiler/Optimize.py
Cython/Compiler/Optimize.py
+87
-0
Cython/Compiler/Parsing.py
Cython/Compiler/Parsing.py
+29
-25
tests/errors/extended_unpacking.pyx
tests/errors/extended_unpacking.pyx
+9
-11
tests/errors/nogil.pyx
tests/errors/nogil.pyx
+33
-30
tests/errors/pep448_syntax_1.pyx
tests/errors/pep448_syntax_1.pyx
+10
-0
tests/errors/pep448_syntax_2.pyx
tests/errors/pep448_syntax_2.pyx
+10
-0
tests/errors/pep448_syntax_3.pyx
tests/errors/pep448_syntax_3.pyx
+10
-0
tests/run/pep448_extended_unpacking.pyx
tests/run/pep448_extended_unpacking.pyx
+208
-4
No files found.
CHANGES.rst
View file @
a8683244
...
...
@@ -15,8 +15,7 @@ Features added
* Tracing is supported in ``nogil`` functions/sections and module init code.
* PEP 448 (Additional Unpacking Generalizations) was partially implemented
for function calls, set and dict literals.
* PEP 448 (Additional Unpacking Generalizations) was implemented.
* When generators are used in a Cython module and the module imports the
modules "inspect" and/or "asyncio", Cython enables interoperability by
...
...
Cython/Compiler/ExprNodes.py
View file @
a8683244
...
...
@@ -5617,7 +5617,7 @@ class MergedDictNode(ExprNode):
item
.
generate_disposal_code
(
code
)
item
.
free_temps
(
code
)
for
helper
in
helpers
:
for
helper
in
sorted
(
helpers
)
:
code
.
globalstate
.
use_utility_code
(
UtilityCode
.
load_cached
(
helper
,
"FunctionArguments.c"
))
def
annotate
(
self
,
code
):
...
...
@@ -6161,14 +6161,14 @@ class AttributeNode(ExprNode):
#
#-------------------------------------------------------------------
class
Starred
Target
Node
(
ExprNode
):
class
Starred
Unpacking
Node
(
ExprNode
):
# A starred expression like "*a"
#
# This is only allowed in sequence assignment
targets
such as
# This is only allowed in sequence assignment
or construction
such as
#
# a, *b = (1,2,3,4) => a = 1 ; b = [2,3,4]
#
# and will be
remov
ed during type analysis (or generate an error
# and will be
special cas
ed during type analysis (or generate an error
# if it's found at unexpected places).
#
# target ExprNode
...
...
@@ -6177,17 +6177,22 @@ class StarredTargetNode(ExprNode):
is_starred
=
1
type
=
py_object_type
is_temp
=
1
starred_expr_allowed_here
=
False
def
__init__
(
self
,
pos
,
target
):
ExprNode
.
__init__
(
self
,
pos
)
self
.
target
=
target
ExprNode
.
__init__
(
self
,
pos
,
target
=
target
)
def
analyse_declarations
(
self
,
env
):
error
(
self
.
pos
,
"can use starred expression only as assignment target"
)
if
not
self
.
starred_expr_allowed_here
:
error
(
self
.
pos
,
"starred expression is not allowed here"
)
self
.
target
.
analyse_declarations
(
env
)
def
infer_type
(
self
,
env
):
return
self
.
target
.
infer_type
(
env
)
def
analyse_types
(
self
,
env
):
error
(
self
.
pos
,
"can use starred expression only as assignment target"
)
if
not
self
.
starred_expr_allowed_here
:
error
(
self
.
pos
,
"starred expression is not allowed here"
)
self
.
target
=
self
.
target
.
analyse_types
(
env
)
self
.
type
=
self
.
target
.
type
return
self
...
...
@@ -6246,9 +6251,9 @@ class SequenceNode(ExprNode):
arg
.
analyse_target_declaration
(
env
)
def
analyse_types
(
self
,
env
,
skip_children
=
False
):
for
i
in
range
(
len
(
self
.
args
)
):
arg
=
self
.
args
[
i
]
if
not
skip_children
:
arg
=
arg
.
analyse_types
(
env
)
for
i
,
arg
in
enumerate
(
self
.
args
):
if
not
skip_children
:
arg
=
arg
.
analyse_types
(
env
)
self
.
args
[
i
]
=
arg
.
coerce_to_pyobject
(
env
)
if
self
.
mult_factor
:
self
.
mult_factor
=
self
.
mult_factor
.
analyse_types
(
env
)
...
...
@@ -6258,6 +6263,39 @@ class SequenceNode(ExprNode):
# not setting self.type here, subtypes do this
return
self
def
_create_merge_node_if_necessary
(
self
,
env
):
self
.
_flatten_starred_args
()
if
not
any
(
arg
.
is_starred
for
arg
in
self
.
args
):
return
self
# convert into MergedSequenceNode by building partial sequences
args
=
[]
values
=
[]
for
arg
in
self
.
args
:
if
arg
.
is_starred
:
if
values
:
args
.
append
(
TupleNode
(
values
[
0
].
pos
,
args
=
values
).
analyse_types
(
env
,
skip_children
=
True
))
values
=
[]
args
.
append
(
arg
.
target
)
else
:
values
.
append
(
arg
)
if
values
:
args
.
append
(
TupleNode
(
values
[
0
].
pos
,
args
=
values
).
analyse_types
(
env
,
skip_children
=
True
))
node
=
MergedSequenceNode
(
self
.
pos
,
args
,
self
.
type
)
if
self
.
mult_factor
:
node
=
binop_node
(
self
.
pos
,
'*'
,
node
,
self
.
mult_factor
.
coerce_to_pyobject
(
env
),
inplace
=
True
,
type
=
self
.
type
,
is_temp
=
True
)
return
node
def
_flatten_starred_args
(
self
):
args
=
[]
for
arg
in
self
.
args
:
if
arg
.
is_starred
and
arg
.
target
.
is_sequence_constructor
and
not
arg
.
target
.
mult_factor
:
args
.
extend
(
arg
.
target
.
args
)
else
:
args
.
append
(
arg
)
self
.
args
[:]
=
args
def
may_be_none
(
self
):
return
False
...
...
@@ -6706,16 +6744,23 @@ class TupleNode(SequenceNode):
return
self
if
not
skip_children
:
self
.
args
=
[
arg
.
analyse_types
(
env
)
for
arg
in
self
.
args
]
if
not
self
.
mult_factor
and
not
any
((
arg
.
type
.
is_pyobject
or
arg
.
type
.
is_fused
)
for
arg
in
self
.
args
):
for
i
,
arg
in
enumerate
(
self
.
args
):
if
arg
.
is_starred
:
arg
.
starred_expr_allowed_here
=
True
self
.
args
[
i
]
=
arg
.
analyse_types
(
env
)
if
(
not
self
.
mult_factor
and
not
any
((
arg
.
is_starred
or
arg
.
type
.
is_pyobject
or
arg
.
type
.
is_fused
)
for
arg
in
self
.
args
)):
self
.
type
=
env
.
declare_tuple_type
(
self
.
pos
,
(
arg
.
type
for
arg
in
self
.
args
)).
type
self
.
is_temp
=
1
return
self
node
=
SequenceNode
.
analyse_types
(
self
,
env
,
skip_children
=
True
)
if
not
all
(
child
.
is_literal
for
child
in
node
.
args
):
node
=
node
.
_create_merge_node_if_necessary
(
env
)
if
not
node
.
is_sequence_constructor
:
return
node
if
not
all
(
child
.
is_literal
for
child
in
node
.
args
):
return
node
if
not
node
.
mult_factor
or
(
node
.
mult_factor
.
is_literal
and
isinstance
(
node
.
mult_factor
.
constant_result
,
(
int
,
long
))):
node
.
is_temp
=
False
...
...
@@ -6822,6 +6867,9 @@ class ListNode(SequenceNode):
return
list_type
def
analyse_expressions
(
self
,
env
):
for
arg
in
self
.
args
:
if
arg
.
is_starred
:
arg
.
starred_expr_allowed_here
=
True
node
=
SequenceNode
.
analyse_expressions
(
self
,
env
)
return
node
.
coerce_to_pyobject
(
env
)
...
...
@@ -6833,6 +6881,7 @@ class ListNode(SequenceNode):
release_errors
(
ignore
=
True
)
if
env
.
is_module_scope
:
self
.
in_module_scope
=
True
node
=
node
.
_create_merge_node_if_necessary
(
env
)
return
node
def
coerce_to
(
self
,
dst_type
,
env
):
...
...
@@ -7227,33 +7276,48 @@ class InlinedGeneratorExpressionNode(ScopedExprNode):
self
.
loop
.
generate_execution_code
(
code
)
class
MergedSe
t
Node
(
ExprNode
):
class
MergedSe
quence
Node
(
ExprNode
):
"""
Merge a sequence of iterables into a set.
Merge a sequence of iterables into a set/list/tuple.
The target collection is determined by self.type, which must be set externally.
args [
SetNode or other
ExprNode]
args [ExprNode]
"""
subexprs
=
[
'args'
]
type
=
set_type
is_temp
=
True
gil_message
=
"Constructing Python set"
gil_message
=
"Constructing Python collection"
def
__init__
(
self
,
pos
,
args
,
type
):
if
type
in
(
list_type
,
tuple_type
)
and
args
and
args
[
0
].
is_sequence_constructor
:
# construct a list directly from the first argument that we can then extend
if
args
[
0
].
type
is
not
list_type
:
args
[
0
]
=
ListNode
(
args
[
0
].
pos
,
args
=
args
[
0
].
args
,
is_temp
=
True
)
ExprNode
.
__init__
(
self
,
pos
,
args
=
args
,
type
=
type
)
def
calculate_constant_result
(
self
):
result
=
set
()
result
=
[]
for
item
in
self
.
args
:
if
item
.
is_sequence_constructor
and
item
.
mult_factor
:
if
item
.
mult_factor
.
constant_result
<=
0
:
continue
# otherwise, adding each item once should be enough
if
item
.
is_set_literal
or
item
.
is_sequence_constructor
:
# process items in order
items
=
(
arg
.
constant_result
for
arg
in
item
.
args
)
else
:
items
=
item
.
constant_result
result
.
update
(
items
)
result
.
extend
(
items
)
if
self
.
type
is
set_type
:
result
=
set
(
result
)
elif
self
.
type
is
tuple_type
:
result
=
tuple
(
result
)
else
:
assert
self
.
type
is
list_type
self
.
constant_result
=
result
def
compile_time_value
(
self
,
denv
):
result
=
set
()
result
=
[]
for
item
in
self
.
args
:
if
item
.
is_sequence_constructor
and
item
.
mult_factor
:
if
item
.
mult_factor
.
compile_time_value
(
denv
)
<=
0
:
...
...
@@ -7263,17 +7327,23 @@ class MergedSetNode(ExprNode):
items
=
(
arg
.
compile_time_value
(
denv
)
for
arg
in
item
.
args
)
else
:
items
=
item
.
compile_time_value
(
denv
)
result
.
extend
(
items
)
if
self
.
type
is
set_type
:
try
:
result
.
update
(
items
)
result
=
set
(
result
)
except
Exception
as
e
:
self
.
compile_time_value_error
(
e
)
elif
self
.
type
is
tuple_type
:
result
=
tuple
(
result
)
else
:
assert
self
.
type
is
list_type
return
result
def
type_dependencies
(
self
,
env
):
return
()
def
infer_type
(
self
,
env
):
return
se
t_
type
return
se
lf
.
type
def
analyse_types
(
self
,
env
):
args
=
[
...
...
@@ -7283,10 +7353,12 @@ class MergedSetNode(ExprNode):
for
arg
in
self
.
args
]
if
len
(
args
)
==
1
and
args
[
0
].
type
is
se
t_
type
:
# strip this intermediate node and use the bare
set
if
len
(
args
)
==
1
and
args
[
0
].
type
is
se
lf
.
type
:
# strip this intermediate node and use the bare
collection
return
args
[
0
]
assert
self
.
type
in
(
set_type
,
list_type
,
tuple_type
)
self
.
args
=
args
return
self
...
...
@@ -7297,40 +7369,79 @@ class MergedSetNode(ExprNode):
code
.
mark_pos
(
self
.
pos
)
self
.
allocate_temp_result
(
code
)
is_set
=
self
.
type
is
set_type
args
=
iter
(
self
.
args
)
item
=
next
(
args
)
item
.
generate_evaluation_code
(
code
)
if
item
.
is_set_literal
:
if
item
.
pos
[
1
]
==
140
:
print
item
.
type
,
item
.
dump
()
if
(
is_set
and
item
.
is_set_literal
or
not
is_set
and
item
.
is_sequence_constructor
and
item
.
type
is
list_type
):
code
.
putln
(
"%s = %s;"
%
(
self
.
result
(),
item
.
py_result
()))
item
.
generate_post_assignment_code
(
code
)
else
:
code
.
putln
(
"%s =
PySet_New
(%s); %s"
%
(
code
.
putln
(
"%s =
%s
(%s); %s"
%
(
self
.
result
(),
'PySet_New'
if
is_set
else
'PySequence_List'
,
item
.
py_result
(),
code
.
error_goto_if_null
(
self
.
result
(),
self
.
pos
)))
code
.
put_gotref
(
self
.
py_result
())
item
.
generate_disposal_code
(
code
)
item
.
free_temps
(
code
)
helpers
=
set
()
if
is_set
:
add_func
=
"PySet_Add"
extend_func
=
"__Pyx_PySet_Update"
else
:
add_func
=
"__Pyx_ListComp_Append"
extend_func
=
"__Pyx_PyList_Extend"
for
item
in
args
:
if
item
.
is_set_literal
or
(
item
.
is_sequence_constructor
and
not
item
.
mult_factor
):
if
(
is_set
and
(
item
.
is_set_literal
or
item
.
is_sequence_constructor
)
or
(
item
.
is_sequence_constructor
and
not
item
.
mult_factor
)):
if
not
is_set
and
item
.
args
:
helpers
.
add
((
"ListCompAppend"
,
"Optimize.c"
))
for
arg
in
item
.
args
:
arg
.
generate_evaluation_code
(
code
)
code
.
put_error_if_neg
(
arg
.
pos
,
"PySet_Add(%s, %s)"
%
(
code
.
put_error_if_neg
(
arg
.
pos
,
"%s(%s, %s)"
%
(
add_func
,
self
.
result
(),
arg
.
py_result
()))
arg
.
generate_disposal_code
(
code
)
arg
.
free_temps
(
code
)
continue
if
is_set
:
helpers
.
add
((
"PySet_Update"
,
"Builtins.c"
))
else
:
helpers
.
add
((
"ListExtend"
,
"Optimize.c"
))
item
.
generate_evaluation_code
(
code
)
code
.
globalstate
.
use_utility_code
(
UtilityCode
.
load_cached
(
"PySet_Update"
,
"Builtins.c"
))
code
.
put_error_if_neg
(
item
.
pos
,
"__Pyx_PySet_Update(%s, %s)"
%
(
code
.
put_error_if_neg
(
item
.
pos
,
"%s(%s, %s)"
%
(
extend_func
,
self
.
result
(),
item
.
py_result
()))
item
.
generate_disposal_code
(
code
)
item
.
free_temps
(
code
)
if
self
.
type
is
tuple_type
:
code
.
putln
(
"{"
)
code
.
putln
(
"PyObject *%s = PyList_AsTuple(%s);"
%
(
Naming
.
quick_temp_cname
,
self
.
result
()))
code
.
put_decref
(
self
.
result
(),
py_object_type
)
code
.
putln
(
"%s = %s; %s"
%
(
self
.
result
(),
Naming
.
quick_temp_cname
,
code
.
error_goto_if_null
(
self
.
result
(),
self
.
pos
)))
code
.
put_gotref
(
self
.
result
())
code
.
putln
(
"}"
)
for
helper
in
sorted
(
helpers
):
code
.
globalstate
.
use_utility_code
(
UtilityCode
.
load_cached
(
*
helper
))
def
annotate
(
self
,
code
):
for
item
in
self
.
args
:
item
.
annotate
(
code
)
...
...
Cython/Compiler/Optimize.py
View file @
a8683244
...
...
@@ -3833,6 +3833,93 @@ class ConstantFolding(Visitor.VisitorTransform, SkipDeclarations):
sequence_node
.
mult_factor
=
factor
return
sequence_node
def
visit_MergedDictNode
(
self
,
node
):
"""Unpack **args in place if we can."""
self
.
visitchildren
(
node
)
args
=
[]
items
=
[]
def
add
(
arg
):
if
arg
.
is_dict_literal
:
if
items
:
items
[
0
].
key_value_pairs
.
extend
(
arg
.
key_value_pairs
)
else
:
items
.
append
(
arg
)
elif
isinstance
(
arg
,
ExprNodes
.
MergedDictNode
):
for
child_arg
in
arg
.
keyword_args
:
add
(
child_arg
)
else
:
if
items
:
args
.
append
(
items
[
0
])
del
items
[:]
args
.
append
(
arg
)
for
arg
in
node
.
keyword_args
:
add
(
arg
)
if
items
:
args
.
append
(
items
[
0
])
if
len
(
args
)
==
1
:
arg
=
args
[
0
]
if
arg
.
is_dict_literal
or
isinstance
(
arg
,
ExprNodes
.
MergedDictNode
):
return
arg
node
.
keyword_args
[:]
=
args
self
.
_calculate_const
(
node
)
return
node
def
visit_MergedSequenceNode
(
self
,
node
):
"""Unpack *args in place if we can."""
self
.
visitchildren
(
node
)
is_set
=
node
.
type
is
Builtin
.
set_type
args
=
[]
values
=
[]
def
add
(
arg
):
if
(
is_set
and
arg
.
is_set_literal
)
or
(
arg
.
is_sequence_constructor
and
not
arg
.
mult_factor
):
if
values
:
values
[
0
].
args
.
extend
(
arg
.
args
)
else
:
values
.
append
(
arg
)
elif
isinstance
(
arg
,
ExprNodes
.
MergedSequenceNode
):
for
child_arg
in
arg
.
args
:
add
(
child_arg
)
else
:
if
values
:
args
.
append
(
values
[
0
])
del
values
[:]
args
.
append
(
arg
)
for
arg
in
node
.
args
:
add
(
arg
)
if
values
:
args
.
append
(
values
[
0
])
if
len
(
args
)
==
1
:
arg
=
args
[
0
]
if
((
is_set
and
arg
.
is_set_literal
)
or
(
arg
.
is_sequence_constructor
and
arg
.
type
is
node
.
type
)
or
isinstance
(
arg
,
ExprNodes
.
MergedSequenceNode
)):
return
arg
node
.
args
[:]
=
args
self
.
_calculate_const
(
node
)
return
node
def
visit_SequenceNode
(
self
,
node
):
"""Unpack *args in place if we can."""
self
.
visitchildren
(
node
)
args
=
[]
for
arg
in
node
.
args
:
if
not
arg
.
is_starred
:
args
.
append
(
arg
)
elif
arg
.
target
.
is_sequence_constructor
and
not
arg
.
target
.
mult_factor
:
args
.
extend
(
arg
.
target
.
args
)
else
:
args
.
append
(
arg
)
node
.
args
[:]
=
args
self
.
_calculate_const
(
node
)
return
node
def
visit_PrimaryCmpNode
(
self
,
node
):
# calculate constant partial results in the comparison cascade
self
.
visitchildren
(
node
,
[
'operand1'
])
...
...
Cython/Compiler/Parsing.py
View file @
a8683244
...
...
@@ -210,7 +210,7 @@ def p_starred_expr(s):
starred
=
False
expr
=
p_bit_expr
(
s
)
if
starred
:
expr
=
ExprNodes
.
Starred
Target
Node
(
pos
,
expr
)
expr
=
ExprNodes
.
Starred
Unpacking
Node
(
pos
,
expr
)
return
expr
def
p_cascaded_cmp
(
s
):
...
...
@@ -915,11 +915,13 @@ def p_string_literal(s, kind_override=None):
s
.
next
()
return
(
kind
,
bytes_value
,
unicode_value
)
# list_display ::= "[" [listmaker] "]"
# listmaker ::= expression ( comp_for | ( "," expression )* [","] )
# since PEP 448:
# list_display ::= "[" [listmaker] "]"
# listmaker ::= (test|star_expr) ( comp_for | (',' (test|star_expr))* [','] )
# comp_iter ::= comp_for | comp_if
# comp_for ::= "for" expression_list "in" testlist [comp_iter]
# comp_if ::= "if" test [comp_iter]
# comp_for
::= "for" expression_list "in" testlist [comp_iter]
# comp_if
::= "if" test [comp_iter]
def
p_list_maker
(
s
):
# s.sy == '['
...
...
@@ -927,24 +929,29 @@ def p_list_maker(s):
s
.
next
()
if
s
.
sy
==
']'
:
s
.
expect
(
']'
)
return
ExprNodes
.
ListNode
(
pos
,
args
=
[])
expr
=
p_test
(
s
)
return
ExprNodes
.
ListNode
(
pos
,
args
=
[])
expr
=
p_test_or_starred_expr
(
s
)
if
s
.
sy
==
'for'
:
if
expr
.
is_starred
:
s
.
error
(
"iterable unpacking cannot be used in comprehension"
)
append
=
ExprNodes
.
ComprehensionAppendNode
(
pos
,
expr
=
expr
)
loop
=
p_comp_for
(
s
,
append
)
s
.
expect
(
']'
)
return
ExprNodes
.
ComprehensionNode
(
pos
,
loop
=
loop
,
append
=
append
,
type
=
Builtin
.
list_type
,
pos
,
loop
=
loop
,
append
=
append
,
type
=
Builtin
.
list_type
,
# list comprehensions leak their loop variable in Py2
has_local_scope
=
s
.
context
.
language_level
>=
3
)
has_local_scope
=
s
.
context
.
language_level
>=
3
)
# (merged) list literal
if
s
.
sy
==
','
:
s
.
next
()
exprs
=
p_test_or_starred_expr_list
(
s
,
expr
)
else
:
if
s
.
sy
==
','
:
s
.
next
()
exprs
=
p_simple_expr_list
(
s
,
expr
)
else
:
exprs
=
[
expr
]
s
.
expect
(
']'
)
return
ExprNodes
.
ListNode
(
pos
,
args
=
exprs
)
exprs
=
[
expr
]
s
.
expect
(
']'
)
return
ExprNodes
.
ListNode
(
pos
,
args
=
exprs
)
def
p_comp_iter
(
s
,
body
):
if
s
.
sy
==
'for'
:
...
...
@@ -1000,7 +1007,9 @@ def p_dict_or_set_maker(s):
s
.
error
(
"unexpected %sitem found in %s literal"
%
(
s
.
sy
,
'set'
if
target_type
==
1
else
'dict'
))
s
.
next
()
item
=
p_test
(
s
)
if
s
.
sy
==
'*'
:
s
.
error
(
"expected expression, found '*'"
)
item
=
p_starred_expr
(
s
)
parts
.
append
(
item
)
last_was_simple_item
=
False
else
:
...
...
@@ -1058,9 +1067,6 @@ def p_dict_or_set_maker(s):
for
part
in
parts
:
if
isinstance
(
part
,
list
):
set_items
.
extend
(
part
)
elif
part
.
is_set_literal
or
part
.
is_sequence_constructor
:
# unpack *{1,2,3} and *[1,2,3] in place
set_items
.
extend
(
part
.
args
)
else
:
if
set_items
:
items
.
append
(
ExprNodes
.
SetNode
(
set_items
[
0
].
pos
,
args
=
set_items
))
...
...
@@ -1070,7 +1076,7 @@ def p_dict_or_set_maker(s):
items
.
append
(
ExprNodes
.
SetNode
(
set_items
[
0
].
pos
,
args
=
set_items
))
if
len
(
items
)
==
1
and
items
[
0
].
is_set_literal
:
return
items
[
0
]
return
ExprNodes
.
MergedSe
tNode
(
pos
,
args
=
items
)
return
ExprNodes
.
MergedSe
quenceNode
(
pos
,
args
=
items
,
type
=
Builtin
.
set_type
)
else
:
# (merged) dict literal
items
=
[]
...
...
@@ -1078,9 +1084,6 @@ def p_dict_or_set_maker(s):
for
part
in
parts
:
if
isinstance
(
part
,
list
):
dict_items
.
extend
(
part
)
elif
part
.
is_dict_literal
:
# unpack **{...} in place
dict_items
.
extend
(
part
.
key_value_pairs
)
else
:
if
dict_items
:
items
.
append
(
ExprNodes
.
DictNode
(
dict_items
[
0
].
pos
,
key_value_pairs
=
dict_items
))
...
...
@@ -1118,10 +1121,11 @@ def p_simple_expr_list(s, expr=None):
s
.
next
()
return
exprs
def
p_test_or_starred_expr_list
(
s
,
expr
=
None
):
exprs
=
expr
is
not
None
and
[
expr
]
or
[]
while
s
.
sy
not
in
expr_terminators
:
exprs
.
append
(
p_test_or_starred_expr
(
s
)
)
exprs
.
append
(
p_test_or_starred_expr
(
s
)
)
if
s
.
sy
!=
','
:
break
s
.
next
()
...
...
tests/errors/extended_unpacking.pyx
View file @
a8683244
...
...
@@ -16,6 +16,8 @@ def syntax1():
[
*
a
,
*
b
]
(
a
,
b
,
*
c
,
d
,
e
,
f
,
*
g
,
h
,
i
)
[
a
,
b
,
*
c
,
d
,
e
,
f
,
*
g
,
h
,
i
]
{
a
,
b
,
*
c
,
d
,
e
,
f
,
*
g
,
h
,
i
}
def
syntax2
():
...
...
@@ -33,19 +35,15 @@ def types(l):
_ERRORS
=
u"""
# syntax1()
8: 4: can use starred expression only as assignment target
10: 4: can use starred expression only as assignment target
12: 4: can use starred expression only as assignment target
14: 4: can use starred expression only as assignment target
16: 5: can use starred expression only as assignment target
16: 9: can use starred expression only as assignment target
18:11: can use starred expression only as assignment target
18:24: can use starred expression only as assignment target
8: 4: starred expression is not allowed here
10: 4: starred expression is not allowed here
12: 4: starred expression is not allowed here
14: 4: starred expression is not allowed here
# syntax2()
2
4
:11: more than 1 starred expression in assignment
2
6
:11: more than 1 starred expression in assignment
# types()
3
0
:15: Cannot coerce list to type 'int'
3
1
:10: starred target must have Python object (list) type
3
2
:15: Cannot coerce list to type 'int'
3
3
:10: starred target must have Python object (list) type
"""
tests/errors/nogil.pyx
View file @
a8683244
...
...
@@ -42,6 +42,7 @@ cdef object m():
(
x
,
y
)
[
x
,
y
]
{
x
:
y
}
{
x
,
y
}
obj
and
x
t
(
obj
)
# f(42) # Cython handles this internally
...
...
@@ -129,35 +130,37 @@ _ERRORS = u"""
42:9: Discarding owned Python object not allowed without gil
43:8: Constructing Python list not allowed without gil
43:8: Discarding owned Python object not allowed without gil
44:8: Constructing Python dict not allowed without gil
44:8: Discarding owned Python object not allowed without gil
45:12: Discarding owned Python object not allowed without gil
45:12: Truth-testing Python object not allowed without gil
46:13: Python type test not allowed without gil
48:10: Discarding owned Python object not allowed without gil
48:10: Operation not allowed without gil
49:8: Discarding owned Python object not allowed without gil
49:8: Operation not allowed without gil
50:10: Assignment of Python object not allowed without gil
50:14: Assignment of Python object not allowed without gil
51:9: Assignment of Python object not allowed without gil
51:13: Assignment of Python object not allowed without gil
51:16: Creating temporary Python reference not allowed without gil
51:19: Creating temporary Python reference not allowed without gil
52:11: Assignment of Python object not allowed without gil
52:11: Indexing Python object not allowed without gil
53:11: Accessing Python attribute not allowed without gil
44:10: Constructing Python dict not allowed without gil
44:10: Discarding owned Python object not allowed without gil
45:10: Constructing Python set not allowed without gil
45:10: Discarding owned Python object not allowed without gil
46:12: Discarding owned Python object not allowed without gil
46:12: Truth-testing Python object not allowed without gil
47:13: Python type test not allowed without gil
49:10: Discarding owned Python object not allowed without gil
49:10: Operation not allowed without gil
50:8: Discarding owned Python object not allowed without gil
50:8: Operation not allowed without gil
51:10: Assignment of Python object not allowed without gil
51:14: Assignment of Python object not allowed without gil
52:9: Assignment of Python object not allowed without gil
52:13: Assignment of Python object not allowed without gil
52:16: Creating temporary Python reference not allowed without gil
52:19: Creating temporary Python reference not allowed without gil
53:11: Assignment of Python object not allowed without gil
54:8: Constructing Python tuple not allowed without gil
54:8: Python print statement not allowed without gil
55:8: Deleting Python object not allowed without gil
56:8: Returning Python object not allowed without gil
57:8: Raising exception not allowed without gil
58:14: Truth-testing Python object not allowed without gil
60:17: Truth-testing Python object not allowed without gil
62:8: For-loop using object bounds or target not allowed without gil
62:14: Coercion from Python not allowed without the GIL
62:25: Coercion from Python not allowed without the GIL
64:8: Try-except statement not allowed without gil
85:8: For-loop using object bounds or target not allowed without gil
53:11: Indexing Python object not allowed without gil
54:11: Accessing Python attribute not allowed without gil
54:11: Assignment of Python object not allowed without gil
55:8: Constructing Python tuple not allowed without gil
55:8: Python print statement not allowed without gil
56:8: Deleting Python object not allowed without gil
57:8: Returning Python object not allowed without gil
58:8: Raising exception not allowed without gil
59:14: Truth-testing Python object not allowed without gil
61:17: Truth-testing Python object not allowed without gil
63:8: For-loop using object bounds or target not allowed without gil
63:14: Coercion from Python not allowed without the GIL
63:25: Coercion from Python not allowed without the GIL
65:8: Try-except statement not allowed without gil
86:8: For-loop using object bounds or target not allowed without gil
"""
tests/errors/pep448_syntax_1.pyx
0 → 100644
View file @
a8683244
# mode: error
# tag: pep448
def
unpack_mix
():
[
*
1
,
**
1
]
_ERRORS
=
"""
5:9: Expected an identifier or literal
"""
tests/errors/pep448_syntax_2.pyx
0 → 100644
View file @
a8683244
# mode: error
# tag: pep448
def
unpack_wrong_stars
():
[
**
1
]
_ERRORS
=
"""
5:5: Expected an identifier or literal
"""
tests/errors/pep448_syntax_3.pyx
0 → 100644
View file @
a8683244
# mode: error
# tag: pep448
def
unpack_mix_in_set
():
{
*
1
,
**
2
}
_ERRORS
=
"""
5:9: unexpected **item found in set literal
"""
tests/run/pep448_extended_unpacking.pyx
View file @
a8683244
...
...
@@ -23,10 +23,200 @@ class Map(object):
return
self
.
mapping
[
key
]
#### tuples
@
cython
.
test_fail_if_path_exists
(
"//TupleNode//TupleNode"
,
"//MergedSequenceNode"
,
)
def
unpack_tuple_literal
():
"""
>>> unpack_tuple_literal()
(1, 2, 4, 5)
"""
return
(
*
(
1
,
2
,
*
(
4
,
5
)),)
def
unpack_tuple_literal_mult
():
"""
>>> unpack_tuple_literal_mult()
(1, 2, 4, 5, 4, 5, 1, 2, 4, 5, 4, 5, 1, 2, 4, 5, 4, 5)
"""
return
(
*
((
1
,
2
,
*
((
4
,
5
)
*
2
))
*
3
),)
@
cython
.
test_fail_if_path_exists
(
"//TupleNode//TupleNode"
,
"//MergedSequenceNode"
,
)
def
unpack_tuple_literal_empty
():
"""
>>> unpack_tuple_literal_empty()
()
"""
return
(
*
(
*
(),
*
()),
*
(),
*
(
*
(
*
(),),))
def
unpack_tuple_simple
(
it
):
"""
>>> unpack_tuple_simple([])
()
>>> unpack_tuple_simple(set())
()
>>> unpack_tuple_simple(Iter())
()
>>> unpack_tuple_simple([1])
(1,)
>>> unpack_tuple_simple([2, 1])
(2, 1)
>>> unpack_tuple_simple((2, 1))
(2, 1)
>>> sorted(unpack_tuple_simple(set([2, 1])))
[1, 2]
>>> unpack_tuple_simple(Iter([2, 1]))
(2, 1)
"""
return
(
*
it
,)
def
unpack_tuple_from_iterable
(
it
):
"""
>>> unpack_tuple_from_iterable([1, 2, 3])
(1, 2, 1, 2, 3, 1, 1, 2, 3, 1, 2, 3, 1, 2, 3, 2, 1, 1, 2, 3)
>>> unpack_tuple_from_iterable((1, 2, 3))
(1, 2, 1, 2, 3, 1, 1, 2, 3, 1, 2, 3, 1, 2, 3, 2, 1, 1, 2, 3)
>>> sorted(unpack_tuple_from_iterable(set([1, 2, 3])))
[1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3]
>>> unpack_tuple_from_iterable([1, 2])
(1, 2, 1, 2, 1, 1, 2, 1, 2, 1, 2, 2, 1, 1, 2)
>>> sorted(unpack_tuple_from_iterable(set([1, 2])))
[1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2]
>>> unpack_tuple_from_iterable(Iter([1, 2]))
(1, 2, 1, 2, 1, 2, 1)
>>> unpack_tuple_from_iterable([3])
(1, 2, 3, 1, 3, 3, 3, 2, 1, 3)
>>> unpack_tuple_from_iterable(set([3]))
(1, 2, 3, 1, 3, 3, 3, 2, 1, 3)
>>> unpack_tuple_from_iterable(Iter([3]))
(1, 2, 3, 1, 2, 1)
>>> unpack_tuple_from_iterable([])
(1, 2, 1, 2, 1)
>>> unpack_tuple_from_iterable(set([]))
(1, 2, 1, 2, 1)
>>> unpack_tuple_from_iterable([])
(1, 2, 1, 2, 1)
>>> unpack_tuple_from_iterable(Iter([1, 2, 3]))
(1, 2, 1, 2, 3, 1, 2, 1)
"""
return
(
1
,
2
,
*
it
,
1
,
*
(
*
it
,
*
it
),
*
it
,
2
,
1
,
*
it
)
#### lists
@
cython
.
test_fail_if_path_exists
(
"//ListNode//ListNode"
,
"//MergedSequenceNode"
,
)
def
unpack_list_literal
():
"""
>>> unpack_list_literal()
[1, 2, 4, 5]
"""
return
[
*
[
1
,
2
,
*
[
4
,
5
]]]
def
unpack_list_literal_mult
():
"""
>>> unpack_list_literal_mult()
[1, 2, 4, 5, 4, 5, 1, 2, 4, 5, 4, 5, 1, 2, 4, 5, 4, 5]
"""
return
[
*
([
1
,
2
,
*
([
4
,
5
]
*
2
)]
*
3
)]
@
cython
.
test_fail_if_path_exists
(
"//ListNode//ListNode"
,
"//MergedSequenceNode"
,
)
def
unpack_list_literal_empty
():
"""
>>> unpack_list_literal_empty()
[]
"""
return
[
*
[
*
[],
*
[]],
*
[],
*
[
*
[
*
[]]]]
def
unpack_list_simple
(
it
):
"""
>>> unpack_list_simple([])
[]
>>> unpack_list_simple(set())
[]
>>> unpack_list_simple(Iter())
[]
>>> unpack_list_simple([1])
[1]
>>> unpack_list_simple([2, 1])
[2, 1]
>>> unpack_list_simple((2, 1))
[2, 1]
>>> sorted(unpack_list_simple(set([2, 1])))
[1, 2]
>>> unpack_list_simple(Iter([2, 1]))
[2, 1]
"""
return
[
*
it
]
def
unpack_list_from_iterable
(
it
):
"""
>>> unpack_list_from_iterable([1, 2, 3])
[1, 2, 1, 2, 3, 1, 1, 2, 3, 1, 2, 3, 1, 2, 3, 2, 1, 1, 2, 3]
>>> unpack_list_from_iterable((1, 2, 3))
[1, 2, 1, 2, 3, 1, 1, 2, 3, 1, 2, 3, 1, 2, 3, 2, 1, 1, 2, 3]
>>> sorted(unpack_list_from_iterable(set([1, 2, 3])))
[1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3]
>>> unpack_list_from_iterable([1, 2])
[1, 2, 1, 2, 1, 1, 2, 1, 2, 1, 2, 2, 1, 1, 2]
>>> sorted(unpack_list_from_iterable(set([1, 2])))
[1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2]
>>> unpack_list_from_iterable(Iter([1, 2]))
[1, 2, 1, 2, 1, 2, 1]
>>> unpack_list_from_iterable([3])
[1, 2, 3, 1, 3, 3, 3, 2, 1, 3]
>>> unpack_list_from_iterable(set([3]))
[1, 2, 3, 1, 3, 3, 3, 2, 1, 3]
>>> unpack_list_from_iterable(Iter([3]))
[1, 2, 3, 1, 2, 1]
>>> unpack_list_from_iterable([])
[1, 2, 1, 2, 1]
>>> unpack_list_from_iterable(set([]))
[1, 2, 1, 2, 1]
>>> unpack_list_from_iterable([])
[1, 2, 1, 2, 1]
>>> unpack_list_from_iterable(Iter([1, 2, 3]))
[1, 2, 1, 2, 3, 1, 2, 1]
"""
return
[
1
,
2
,
*
it
,
1
,
*
[
*
it
,
*
it
],
*
it
,
2
,
1
,
*
it
]
###### sets
@
cython
.
test_fail_if_path_exists
(
"//SetNode//SetNode"
,
"//MergedSetNode//SetNode"
,
"//MergedSetNode//MergedSetNode"
,
"//MergedSequenceNode"
,
)
def
unpack_set_literal
():
"""
...
...
@@ -131,10 +321,12 @@ def unpack_set_from_iterable(it):
return
{
1
,
2
,
*
it
,
1
,
*
{
*
it
,
*
it
},
*
it
,
2
,
1
,
*
it
,
*
it
}
#### dicts
@
cython
.
test_fail_if_path_exists
(
"//DictNode//DictNode"
,
"//MergedDictNode//DictNode"
,
"//MergedDictNode//MergedDictNode"
,
"//MergedDictNode"
,
)
def
unpack_dict_literal
():
"""
...
...
@@ -145,6 +337,18 @@ def unpack_dict_literal():
return
{
**
{
'a'
:
1
,
'b'
:
2
,
**
{
'c'
:
4
,
'd'
:
5
}}}
@
cython
.
test_fail_if_path_exists
(
"//DictNode//DictNode"
,
"//MergedDictNode"
,
)
def
unpack_dict_literal_empty
():
"""
>>> unpack_dict_literal_empty()
{}
"""
return
{
**
{
**
{},
**
{}},
**
{},
**
{
**
{
**
{}}}}
def
unpack_dict_simple
(
it
):
"""
>>> d = unpack_dict_simple({})
...
...
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