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
Kirill Smelkov
cython
Commits
c036607a
Commit
c036607a
authored
Apr 12, 2014
by
Stefan Behnel
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
implement support for extracting type declarations from signature annotations
parent
cbe735b8
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
101 additions
and
31 deletions
+101
-31
CHANGES.rst
CHANGES.rst
+3
-0
Cython/Compiler/ExprNodes.py
Cython/Compiler/ExprNodes.py
+30
-17
Cython/Compiler/Nodes.py
Cython/Compiler/Nodes.py
+56
-14
Cython/Compiler/Options.py
Cython/Compiler/Options.py
+2
-0
docs/src/tutorial/pure.rst
docs/src/tutorial/pure.rst
+10
-0
No files found.
CHANGES.rst
View file @
c036607a
...
...
@@ -9,6 +9,9 @@ Latest
Features added
--------------
* Simple support for declaring Python object types in Python signature
annotations.
Bugs fixed
----------
...
...
Cython/Compiler/ExprNodes.py
View file @
c036607a
...
...
@@ -289,15 +289,16 @@ class ExprNode(Node):
#
#
is_sequence_constructor
=
0
is_string_literal
=
0
is_attribute
=
0
is_subscript
=
0
is_sequence_constructor
=
False
is_dict_literal
=
False
is_string_literal
=
False
is_attribute
=
False
is_subscript
=
False
saved_subexpr_nodes
=
None
is_temp
=
0
is_target
=
0
is_starred
=
0
is_temp
=
False
is_target
=
False
is_starred
=
False
constant_result
=
constant_value_not_set
...
...
@@ -1174,6 +1175,20 @@ class FloatNode(ConstNode):
self
.
result_code
=
c_value
def
_analyse_name_as_type
(
name
,
pos
,
env
):
type
=
PyrexTypes
.
parse_basic_type
(
name
)
if
type
is
not
None
:
return
type
from
TreeFragment
import
TreeFragment
pos
=
(
pos
[
0
],
pos
[
1
],
pos
[
2
]
-
7
)
declaration
=
TreeFragment
(
u"sizeof(%s)"
%
name
,
name
=
pos
[
0
].
filename
,
initial_pos
=
pos
)
sizeof_node
=
declaration
.
root
.
stats
[
0
].
expr
sizeof_node
=
sizeof_node
.
analyse_types
(
env
)
if
isinstance
(
sizeof_node
,
SizeofTypeNode
):
return
sizeof_node
.
arg_type
return
None
class
BytesNode
(
ConstNode
):
# A char* or bytes literal
#
...
...
@@ -1196,16 +1211,7 @@ class BytesNode(ConstNode):
return
self
.
value
def
analyse_as_type
(
self
,
env
):
type
=
PyrexTypes
.
parse_basic_type
(
self
.
value
)
if
type
is
not
None
:
return
type
from
TreeFragment
import
TreeFragment
pos
=
(
self
.
pos
[
0
],
self
.
pos
[
1
],
self
.
pos
[
2
]
-
7
)
declaration
=
TreeFragment
(
u"sizeof(%s)"
%
self
.
value
,
name
=
pos
[
0
].
filename
,
initial_pos
=
pos
)
sizeof_node
=
declaration
.
root
.
stats
[
0
].
expr
sizeof_node
=
sizeof_node
.
analyse_types
(
env
)
if
isinstance
(
sizeof_node
,
SizeofTypeNode
):
return
sizeof_node
.
arg_type
return
_analyse_name_as_type
(
self
.
value
.
decode
(
'ISO8859-1'
),
self
.
pos
,
env
)
def
can_coerce_to_char_literal
(
self
):
return
len
(
self
.
value
)
==
1
...
...
@@ -1279,6 +1285,9 @@ class UnicodeNode(ConstNode):
def
calculate_constant_result
(
self
):
self
.
constant_result
=
self
.
value
def
analyse_as_type
(
self
,
env
):
return
_analyse_name_as_type
(
self
.
value
,
self
.
pos
,
env
)
def
as_sliced_node
(
self
,
start
,
stop
,
step
=
None
):
if
StringEncoding
.
string_contains_surrogates
(
self
.
value
[:
stop
]):
# this is unsafe as it may give different results
...
...
@@ -1388,6 +1397,9 @@ class StringNode(PyConstNode):
# only the Unicode value is portable across Py2/3
self
.
constant_result
=
self
.
unicode_value
def
analyse_as_type
(
self
,
env
):
return
_analyse_name_as_type
(
self
.
unicode_value
or
self
.
value
.
decode
(
'ISO8859-1'
),
self
.
pos
,
env
)
def
as_sliced_node
(
self
,
start
,
stop
,
step
=
None
):
value
=
type
(
self
.
value
)(
self
.
value
[
start
:
stop
:
step
])
value
.
encoding
=
self
.
value
.
encoding
...
...
@@ -6706,6 +6718,7 @@ class DictNode(ExprNode):
is_temp
=
1
exclude_null_values
=
False
type
=
dict_type
is_dict_literal
=
True
obj_conversion_errors
=
[]
...
...
Cython/Compiler/Nodes.py
View file @
c036607a
...
...
@@ -612,8 +612,8 @@ class CFuncDeclaratorNode(CDeclaratorNode):
nonempty
-=
1
func_type_args
=
[]
for
i
,
arg_node
in
enumerate
(
self
.
args
):
name_declarator
,
type
=
arg_node
.
analyse
(
env
,
nonempty
=
nonempty
,
is_self_arg
=
(
i
==
0
and
env
.
is_c_class_scope
))
name_declarator
,
type
=
arg_node
.
analyse
(
env
,
nonempty
=
nonempty
,
is_self_arg
=
(
i
==
0
and
env
.
is_c_class_scope
))
name
=
name_declarator
.
name
if
name
in
directive_locals
:
type_node
=
directive_locals
[
name
]
...
...
@@ -800,7 +800,7 @@ class CArgDeclNode(Node):
if
nonempty
:
if
self
.
base_type
.
is_basic_c_type
:
# char, short, long called "int"
type
=
self
.
base_type
.
analyse
(
env
,
could_be_name
=
True
)
type
=
self
.
base_type
.
analyse
(
env
,
could_be_name
=
True
)
arg_name
=
type
.
declaration_code
(
""
)
else
:
arg_name
=
self
.
base_type
.
name
...
...
@@ -811,9 +811,10 @@ class CArgDeclNode(Node):
else
:
could_be_name
=
False
self
.
base_type
.
is_arg
=
True
base_type
=
self
.
base_type
.
analyse
(
env
,
could_be_name
=
could_be_name
)
base_type
=
self
.
base_type
.
analyse
(
env
,
could_be_name
=
could_be_name
)
if
hasattr
(
self
.
base_type
,
'arg_name'
)
and
self
.
base_type
.
arg_name
:
self
.
declarator
.
name
=
self
.
base_type
.
arg_name
# The parser is unable to resolve the ambiguity of [] as part of the
# type (e.g. in buffers) or empty declarator (as with arrays).
# This is only arises for empty multi-dimensional arrays.
...
...
@@ -825,10 +826,45 @@ class CArgDeclNode(Node):
declarator
=
declarator
.
base
declarator
.
base
=
self
.
base_type
.
array_declarator
base_type
=
base_type
.
base_type
return
self
.
declarator
.
analyse
(
base_type
,
env
,
nonempty
=
nonempty
)
# inject type declaration from annotations
if
self
.
annotation
and
env
.
directives
[
'annotation_typing'
]
and
self
.
base_type
.
name
is
None
:
arg_type
=
self
.
inject_type_from_annotations
(
env
)
if
arg_type
is
not
None
:
base_type
=
arg_type
return
self
.
declarator
.
analyse
(
base_type
,
env
,
nonempty
=
nonempty
)
else
:
return
self
.
name_declarator
,
self
.
type
def
inject_type_from_annotations
(
self
,
env
):
annotation
=
self
.
annotation
if
not
annotation
:
return
explicit_pytype
=
explicit_ctype
=
False
if
annotation
.
is_dict_literal
:
for
name
,
value
in
annotation
.
key_value_pairs
:
if
not
name
.
is_string_literal
:
continue
if
name
.
value
==
'type'
:
explicit_pytype
=
True
if
not
explicit_ctype
:
annotation
=
value
elif
name
.
value
==
'ctype'
:
explicit_ctype
=
True
annotation
=
value
if
explicit_pytype
and
explicit_ctype
:
warning
(
annotation
.
pos
,
"Duplicate type declarations found in signature annotation"
)
arg_type
=
annotation
.
analyse_as_type
(
env
)
if
arg_type
is
not
None
:
if
explicit_pytype
and
not
explicit_ctype
and
not
arg_type
.
is_pyobject
:
warning
(
annotation
.
pos
,
"Python type declaration in signature annotation does not refer to a Python type"
)
self
.
base_type
=
CAnalysedBaseTypeNode
(
annotation
.
pos
,
type
=
arg_type
,
is_arg
=
True
)
else
:
warning
(
annotation
.
pos
,
"Unknown type declaration found in signature annotation"
)
return
arg_type
def
calculate_default_value_code
(
self
,
code
):
if
self
.
default_value
is
None
:
if
self
.
default
:
...
...
@@ -1524,19 +1560,25 @@ class FuncDefNode(StatNode, BlockNode):
error
(
arg
.
pos
,
"Non-default argument following default argument"
)
def
align_argument_type
(
self
,
env
,
arg
):
# @cython.locals()
directive_locals
=
self
.
directive_locals
type
=
arg
.
type
orig_
type
=
arg
.
type
if
arg
.
name
in
directive_locals
:
type_node
=
directive_locals
[
arg
.
name
]
other_type
=
type_node
.
analyse_as_type
(
env
)
if
other_type
is
None
:
error
(
type_node
.
pos
,
"Not a type"
)
elif
(
type
is
not
PyrexTypes
.
py_object_type
and
not
type
.
same_as
(
other_type
)):
error
(
arg
.
base_type
.
pos
,
"Signature does not agree with previous declaration"
)
error
(
type_node
.
pos
,
"Previous declaration here"
)
else
:
arg
.
type
=
other_type
elif
isinstance
(
arg
,
CArgDeclNode
)
and
arg
.
annotation
:
type_node
=
arg
.
annotation
other_type
=
arg
.
inject_type_from_annotations
(
env
)
else
:
return
arg
if
other_type
is
None
:
error
(
type_node
.
pos
,
"Not a type"
)
elif
(
orig_type
is
not
PyrexTypes
.
py_object_type
and
not
orig_type
.
same_as
(
other_type
)):
error
(
arg
.
base_type
.
pos
,
"Signature does not agree with previous declaration"
)
error
(
type_node
.
pos
,
"Previous declaration here"
)
else
:
arg
.
type
=
other_type
return
arg
def
need_gil_acquisition
(
self
,
lenv
):
...
...
Cython/Compiler/Options.py
View file @
c036607a
...
...
@@ -101,6 +101,7 @@ directive_defaults = {
'profile'
:
False
,
'no_gc_clear'
:
False
,
'linetrace'
:
False
,
'annotation_typing'
:
False
,
# read type declarations from Python function annotations
'infer_types'
:
None
,
'infer_types.verbose'
:
False
,
'autotestdict'
:
True
,
...
...
@@ -228,6 +229,7 @@ directive_scopes = { # defaults to available everywhere
'test_assert_path_exists'
:
(
'function'
,
'class'
,
'cclass'
),
'test_fail_if_path_exists'
:
(
'function'
,
'class'
,
'cclass'
),
'freelist'
:
(
'cclass'
,),
'annotation_typing'
:
(
'module'
,),
# FIXME: analysis currently lacks more specific function scope
# Avoid scope-specific to/from_py_functions for c_string.
'c_string_type'
:
(
'module'
,),
'c_string_encoding'
:
(
'module'
,),
...
...
docs/src/tutorial/pure.rst
View file @
c036607a
...
...
@@ -36,6 +36,16 @@ The currently supported attributes of the ``cython`` module are:
def foo(a, b, x, y):
...
* Starting with Cython 0.21, Python signature annotations can be used to
declare argument types. Cython recognises three ways to do this, as
shown in the following example::
def func(plain_python_type: dict,
named_python_type: 'dict',
explicit_python_type: {'type': dict},
explicit_c_type: {'ctype': 'int'}):
...
* ``address`` is used in place of the ``&`` operator::
cython.declare(x=cython.int, x_ptr=cython.p_int)
...
...
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