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
Labels
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Commits
Open sidebar
nexedi
cython
Commits
09a61d2a
Commit
09a61d2a
authored
Jun 29, 2015
by
Stefan Behnel
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
make the coercion between C unions and Python dicts usable
parent
372efbe8
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
195 additions
and
2 deletions
+195
-2
CHANGES.rst
CHANGES.rst
+2
-0
Cython/Compiler/PyrexTypes.py
Cython/Compiler/PyrexTypes.py
+19
-2
Cython/Utility/CConvert.pyx
Cython/Utility/CConvert.pyx
+35
-0
tests/errors/e_cunion.pyx
tests/errors/e_cunion.pyx
+29
-0
tests/run/ctuple.pyx
tests/run/ctuple.pyx
+30
-0
tests/run/cunion.pyx
tests/run/cunion.pyx
+80
-0
No files found.
CHANGES.rst
View file @
09a61d2a
...
...
@@ -89,6 +89,8 @@ Bugs fixed
types could overflow for large buffer sizes. Original patch by
David Vierra.
* C unions use a saner way to coerce from and to Python dicts.
Other changes
-------------
...
...
Cython/Compiler/PyrexTypes.py
View file @
09a61d2a
...
...
@@ -3149,11 +3149,27 @@ class CStructOrUnionType(CType):
return
None
# tri-state-ish
if
self
.
_convert_to_py_code
is
None
:
is_union
=
not
self
.
is_struct
unsafe_union_types
=
set
()
safe_union_types
=
set
()
for
member
in
self
.
scope
.
var_entries
:
if
not
member
.
type
.
create_to_py_utility_code
(
env
):
member_type
=
member
.
type
if
not
member_type
.
create_to_py_utility_code
(
env
):
self
.
to_py_function
=
None
self
.
_convert_to_py_code
=
False
return
False
if
is_union
:
if
member_type
.
is_ptr
or
member_type
.
is_cpp_class
:
unsafe_union_types
.
add
(
member_type
)
else
:
safe_union_types
.
add
(
member_type
)
if
unsafe_union_types
and
(
safe_union_types
or
len
(
unsafe_union_types
)
>
1
):
# unsafe mix of safe and unsafe to convert types
self
.
from_py_function
=
None
self
.
_convert_from_py_code
=
False
return
False
forward_decl
=
self
.
entry
.
visibility
!=
'extern'
and
not
self
.
typedef_flag
self
.
_convert_to_py_code
=
ToPyStructUtilityCode
(
self
,
forward_decl
,
env
)
...
...
@@ -3181,7 +3197,8 @@ class CStructOrUnionType(CType):
)
from
.UtilityCode
import
CythonUtilityCode
self
.
_convert_from_py_code
=
CythonUtilityCode
.
load
(
"FromPyStructUtility"
,
"CConvert.pyx"
,
"FromPyStructUtility"
if
self
.
is_struct
else
"FromPyUnionUtility"
,
"CConvert.pyx"
,
outer_module_scope
=
env
.
global_scope
(),
# need access to types declared in module
context
=
context
)
...
...
Cython/Utility/CConvert.pyx
View file @
09a61d2a
...
...
@@ -23,6 +23,41 @@ cdef {{struct_name}} {{funcname}}(obj) except *:
return
result
#################### FromPyUnionUtility ####################
cdef
extern
from
*
:
ctypedef
struct
PyTypeObject
:
char
*
tp_name
PyTypeObject
*
Py_TYPE
(
obj
)
bint
PyMapping_Check
(
obj
)
object
PyErr_Format
(
exc
,
const
char
*
format
,
...)
@
cname
(
"{{funcname}}"
)
cdef
{{
struct_name
}}
{{
funcname
}}(
obj
)
except
*
:
cdef
{{
struct_name
}}
result
cdef
Py_ssize_t
length
if
not
PyMapping_Check
(
obj
):
PyErr_Format
(
TypeError
,
b"Expected %.16s, got %.200s"
,
b"a mapping"
,
Py_TYPE
(
obj
).
tp_name
)
last_found
=
None
length
=
len
(
obj
)
if
length
:
{{
for
member
in
var_entries
:}}
if
'{{member.name}}'
in
obj
:
if
last_found
is
not
None
:
raise
ValueError
(
"More than one union attribute passed: '%s' and '%s'"
%
(
last_found
,
'{{member.name}}'
))
last_found
=
'{{member.name}}'
result
.{{
member
.
cname
}}
=
obj
[
'{{member.name}}'
]
length
-=
1
if
not
length
:
return
result
{{
endfor
}}
if
last_found
is
None
:
raise
ValueError
(
"No value specified for any of the union attributes (%s)"
%
'{{", ".join(member.name for member in var_entries)}}'
)
return
result
#################### cfunc.to_py ####################
@
cname
(
"{{cname}}"
)
...
...
tests/errors/e_cunion.pyx
0 → 100644
View file @
09a61d2a
# mode: error
cdef
union
AllCharptr
:
char
*
s1
char
*
s2
char
*
s3
def
convert_ok
():
cdef
AllCharptr
u
u
.
s1
=
b"abc"
return
u
cdef
union
IllegalMix
:
char
*
s1
char
*
s2
int
i
def
convert_nok
():
cdef
IllegalMix
u
u
.
i
=
5
return
u
_ERRORS
=
"""
24:12: Cannot convert 'IllegalMix' to Python object
"""
tests/run/ctuple.pyx
View file @
09a61d2a
...
...
@@ -76,6 +76,36 @@ def c_types(int a, double b):
a_ptr
,
b_ptr
=
ab
return
a_ptr
[
0
],
b_ptr
[
0
]
cdef
union
Union
:
int
x
double
y
def
union_in_ctuple_literal
():
"""
>>> union_in_ctuple_literal()
(1, 2.0)
"""
cdef
(
Union
,)
a
=
({
"x"
:
1
},)
cdef
(
Union
,)
b
=
({
"y"
:
2
},)
return
a
[
0
].
x
,
b
[
0
].
y
def
union_in_ctuple_dynamic
(
*
values
):
"""
>>> union_in_ctuple_dynamic(1, {'x': 1})
1
>>> union_in_ctuple_dynamic(2, {'y': 2})
2.0
>>> union_in_ctuple_dynamic(1, {'x': 1, 'y': 2})
Traceback (most recent call last):
ValueError: More than one union attribute passed: 'x' and 'y'
"""
cdef
(
int
,
Union
)
a
=
values
return
a
[
1
].
x
if
a
[
0
]
==
1
else
a
[
1
].
y
cdef
(
int
,
int
*
)
cdef
_ctuple_return_type
(
int
x
,
int
*
x_ptr
):
return
x
,
x_ptr
...
...
tests/run/cunion.pyx
View file @
09a61d2a
...
...
@@ -22,6 +22,7 @@ cdef void eggs_p(Spam s):
spam
=
ham
def
test_i
():
"""
>>> test_i()
...
...
@@ -29,6 +30,7 @@ def test_i():
spam
.
i
=
1
eggs_i
(
spam
)
def
test_c
():
"""
>>> test_c()
...
...
@@ -36,6 +38,7 @@ def test_c():
spam
.
c
=
c
'a'
eggs_c
(
spam
)
def
test_p
():
"""
>>> test_p()
...
...
@@ -43,3 +46,80 @@ def test_p():
cdef
float
f
spam
.
p
[
0
]
=
&
f
eggs_p
(
spam
)
cdef
union
AllCharptr
:
char
*
s1
char
*
s2
char
*
s3
def
test_charptr_to_py
():
"""
>>> result = test_charptr_to_py()
>>> len(result)
3
>>> result['s1'] == b'abc'
True
>>> result['s2'] == b'abc'
True
>>> result['s3'] == b'abc'
True
"""
cdef
AllCharptr
u
u
.
s1
=
b"abc"
return
u
cdef
union
SafeMix
:
char
c
unsigned
char
uc
signed
char
sc
short
w
int
i
long
l
size_t
z
float
f
double
d
def
test_safe_type_mix_from_to_py
(
v
):
"""
>>> test_safe_type_mix_from_to_py({'l': 32, 'c': 32})
Traceback (most recent call last):
ValueError: More than one union attribute passed: 'c' and 'l'
>>> result = test_safe_type_mix_from_to_py({'c': 32})
>>> sorted(result)
['c', 'd', 'f', 'i', 'l', 'sc', 'uc', 'w', 'z']
>>> result['c']
32
>>> result['z'] != 0
True
>>> result = test_safe_type_mix_from_to_py({'uc': 32})
>>> len(result)
9
>>> result['uc']
32
>>> result = test_safe_type_mix_from_to_py({'l': 100})
>>> result['l']
100
>>> result = test_safe_type_mix_from_to_py({'z': 0})
>>> result['z']
0
>>> result['i']
0
>>> result['l']
0
>>> result = test_safe_type_mix_from_to_py({'d': 2**52 - 1})
>>> result['d']
4503599627370495.0
>>> result['z'] != 0
True
"""
cdef
SafeMix
u
=
v
return
u
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