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
9ca6532b
Commit
9ca6532b
authored
Feb 16, 2018
by
scoder
Committed by
GitHub
Feb 16, 2018
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1869 from scoder/readonly_buffers
implement read-only memoryviews
parents
83ffbe08
e4838d84
Changes
16
Show whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
371 additions
and
196 deletions
+371
-196
CHANGES.rst
CHANGES.rst
+7
-4
Cython/Compiler/ExprNodes.py
Cython/Compiler/ExprNodes.py
+23
-15
Cython/Compiler/FusedNode.py
Cython/Compiler/FusedNode.py
+2
-2
Cython/Compiler/MemoryView.py
Cython/Compiler/MemoryView.py
+6
-6
Cython/Compiler/Nodes.py
Cython/Compiler/Nodes.py
+10
-19
Cython/Compiler/Parsing.py
Cython/Compiler/Parsing.py
+6
-3
Cython/Compiler/PyrexTypes.py
Cython/Compiler/PyrexTypes.py
+57
-37
Cython/Utility/MemoryView.pyx
Cython/Utility/MemoryView.pyx
+12
-2
Cython/Utility/MemoryView_C.c
Cython/Utility/MemoryView_C.c
+3
-3
docs/src/userguide/memoryviews.rst
docs/src/userguide/memoryviews.rst
+27
-0
tests/buffers/bufaccess.pyx
tests/buffers/bufaccess.pyx
+8
-8
tests/buffers/mockbuffers.pxi
tests/buffers/mockbuffers.pxi
+11
-6
tests/errors/e_arrayassign.pyx
tests/errors/e_arrayassign.pyx
+3
-2
tests/memoryview/memoryview.pyx
tests/memoryview/memoryview.pyx
+1
-1
tests/memoryview/memslice.pyx
tests/memoryview/memslice.pyx
+105
-88
tests/memoryview/numpy_memoryview_readonly.pyx
tests/memoryview/numpy_memoryview_readonly.pyx
+90
-0
No files found.
CHANGES.rst
View file @
9ca6532b
...
...
@@ -8,10 +8,6 @@ Cython Changelog
Features added
--------------
* When compiling with gcc, the module init function is now tuned for small
code size instead of whatever compile flags were provided externally.
(Github issue #2102)
* Cdef classes can now multiply inherit from ordinary Python classes.
(The primary base must still be a c class, possibly ``object``, and
the other bases must *not* be cdef classes.)
...
...
@@ -19,6 +15,13 @@ Features added
* Type inference is now supported for Pythran compiled NumPy expressions.
Patch by Nils Braun. (Github issue #1954)
* The ``const`` modifier can be applied to memoryview declarations to allow
read-only buffers as input. (Github issues #1605, #1869)
* When compiling with gcc, the module init function is now tuned for small
code size instead of whatever compile flags were provided externally.
(Github issue #2102)
* C file includes are moved behind the module declarations if possible, to allow
them to depend on module declarations themselves.
Patch by Jeroen Demeyer. (Github issue #1896)
...
...
Cython/Compiler/ExprNodes.py
View file @
9ca6532b
...
...
@@ -870,7 +870,10 @@ class ExprNode(Node):
elif
not
src_type
.
is_error
:
error
(
self
.
pos
,
"Cannot convert '%s' to memoryviewslice"
%
(
src_type
,))
elif
not
src
.
type
.
conforms_to
(
dst_type
,
broadcast
=
self
.
is_memview_broadcast
,
else
:
if
src
.
type
.
writable_needed
:
dst_type
.
writable_needed
=
True
if
not
src
.
type
.
conforms_to
(
dst_type
,
broadcast
=
self
.
is_memview_broadcast
,
copying
=
self
.
is_memview_copy_assignment
):
if
src
.
type
.
dtype
.
same_as
(
dst_type
.
dtype
):
msg
=
"Memoryview '%s' not conformable to memoryview '%s'."
...
...
@@ -4298,6 +4301,11 @@ class MemoryViewIndexNode(BufferIndexNode):
indices
=
self
.
indices
have_slices
,
indices
,
newaxes
=
MemoryView
.
unellipsify
(
indices
,
self
.
base
.
type
.
ndim
)
if
not
getting
:
self
.
writable_needed
=
True
if
self
.
base
.
is_name
or
self
.
base
.
is_attribute
:
self
.
base
.
entry
.
type
.
writable_needed
=
True
self
.
memslice_index
=
(
not
newaxes
and
len
(
indices
)
==
self
.
base
.
type
.
ndim
)
axes
=
[]
...
...
@@ -12772,12 +12780,12 @@ class CoerceToMemViewSliceNode(CoercionNode):
def
generate_result_code
(
self
,
code
):
self
.
type
.
create_from_py_utility_code
(
self
.
env
)
code
.
putln
(
"%s = %s(%s);"
%
(
self
.
result
(),
self
.
type
.
from_py_function
,
self
.
arg
.
py_result
()))
error_cond
=
self
.
type
.
error_condition
(
self
.
result
())
code
.
putln
(
code
.
error_goto_if
(
error_cond
,
self
.
pos
))
code
.
putln
(
self
.
type
.
from_py_call_code
(
self
.
arg
.
py_result
()
,
self
.
result
(),
self
.
pos
,
code
))
class
CastNode
(
CoercionNode
):
...
...
Cython/Compiler/FusedNode.py
View file @
9ca6532b
...
...
@@ -390,7 +390,7 @@ class FusedCFuncDefNode(StatListNode):
coerce_from_py_func
=
memslice_type
.
from_py_function
,
dtype
=
dtype
)
decl_code
.
putln
(
"{{memviewslice_cname}} {{coerce_from_py_func}}(object)"
)
"{{memviewslice_cname}} {{coerce_from_py_func}}(object
, int
)"
)
pyx_code
.
context
.
update
(
specialized_type_name
=
specialized_type
.
specialization_string
,
...
...
@@ -400,7 +400,7 @@ class FusedCFuncDefNode(StatListNode):
u"""
# try {{dtype}}
if itemsize == -1 or itemsize == {{sizeof_dtype}}:
memslice = {{coerce_from_py_func}}(arg)
memslice = {{coerce_from_py_func}}(arg
, 0
)
if memslice.memview:
__PYX_XDEC_MEMVIEW(&memslice, 1)
# print 'found a match for the buffer through format parsing'
...
...
Cython/Compiler/MemoryView.py
View file @
9ca6532b
...
...
@@ -28,12 +28,12 @@ def concat_flags(*flags):
format_flag
=
"PyBUF_FORMAT"
memview_c_contiguous
=
"(PyBUF_C_CONTIGUOUS | PyBUF_FORMAT
| PyBUF_WRITABLE
)"
memview_f_contiguous
=
"(PyBUF_F_CONTIGUOUS | PyBUF_FORMAT
| PyBUF_WRITABLE
)"
memview_any_contiguous
=
"(PyBUF_ANY_CONTIGUOUS | PyBUF_FORMAT
| PyBUF_WRITABLE
)"
memview_full_access
=
"PyBUF_FULL"
#memview_strided_access = "PyBUF_STRIDED"
memview_strided_access
=
"PyBUF_RECORDS"
memview_c_contiguous
=
"(PyBUF_C_CONTIGUOUS | PyBUF_FORMAT)"
memview_f_contiguous
=
"(PyBUF_F_CONTIGUOUS | PyBUF_FORMAT)"
memview_any_contiguous
=
"(PyBUF_ANY_CONTIGUOUS | PyBUF_FORMAT)"
memview_full_access
=
"PyBUF_FULL
_RO
"
#memview_strided_access = "PyBUF_STRIDED
_RO
"
memview_strided_access
=
"PyBUF_RECORDS
_RO
"
MEMVIEW_DIRECT
=
'__Pyx_MEMVIEW_DIRECT'
MEMVIEW_PTR
=
'__Pyx_MEMVIEW_PTR'
...
...
Cython/Compiler/Nodes.py
View file @
9ca6532b
...
...
@@ -3753,18 +3753,12 @@ class DefNodeWrapper(FuncDefNode):
entry
=
arg
.
entry
code
.
putln
(
"%s = %s;"
%
(
entry
.
cname
,
item
))
else
:
func
=
arg
.
type
.
from_py_function
if
func
:
if
arg
.
type
.
from_py_function
:
if
arg
.
default
:
# C-typed default arguments must be handled here
code
.
putln
(
'if (%s) {'
%
item
)
rhs
=
"%s(%s)"
%
(
func
,
item
)
if
arg
.
type
.
is_enum
:
rhs
=
arg
.
type
.
cast_code
(
rhs
)
code
.
putln
(
"%s = %s; %s"
%
(
arg
.
entry
.
cname
,
rhs
,
code
.
error_goto_if
(
arg
.
type
.
error_condition
(
arg
.
entry
.
cname
),
arg
.
pos
)))
code
.
putln
(
arg
.
type
.
from_py_call_code
(
item
,
arg
.
entry
.
cname
,
arg
.
pos
,
code
))
if
arg
.
default
:
code
.
putln
(
'} else {'
)
code
.
putln
(
"%s = %s;"
%
(
...
...
@@ -4005,17 +3999,14 @@ class DefNodeWrapper(FuncDefNode):
def
generate_arg_conversion_from_pyobject
(
self
,
arg
,
code
):
new_type
=
arg
.
type
func
=
new_type
.
from_py_function
# copied from CoerceFromPyTypeNode
if
func
:
lhs
=
arg
.
entry
.
cname
rhs
=
"%s(%s)"
%
(
func
,
arg
.
hdr_cname
)
if
new_type
.
is_enum
:
rhs
=
PyrexTypes
.
typecast
(
new_type
,
PyrexTypes
.
c_long_type
,
rhs
)
code
.
putln
(
"%s = %s; %s"
%
(
lhs
,
rhs
,
code
.
error_goto_if
(
new_type
.
error_condition
(
arg
.
entry
.
cname
),
arg
.
pos
)))
if
new_type
.
from_py_function
:
code
.
putln
(
new_type
.
from_py_call_code
(
arg
.
hdr_cname
,
arg
.
entry
.
cname
,
arg
.
pos
,
code
,
))
else
:
error
(
arg
.
pos
,
"Cannot convert Python object argument to type '%s'"
%
new_type
)
...
...
Cython/Compiler/Parsing.py
View file @
9ca6532b
...
...
@@ -2481,9 +2481,12 @@ def p_c_simple_base_type(s, self_flag, nonempty, templates = None):
error
(
pos
,
"Expected an identifier, found '%s'"
%
s
.
sy
)
if
s
.
systring
==
'const'
:
s
.
next
()
base_type
=
p_c_base_type
(
s
,
self_flag
=
self_flag
,
nonempty
=
nonempty
,
templates
=
templates
)
return
Nodes
.
CConstTypeNode
(
pos
,
base_type
=
base_type
)
base_type
=
p_c_base_type
(
s
,
self_flag
=
self_flag
,
nonempty
=
nonempty
,
templates
=
templates
)
if
isinstance
(
base_type
,
Nodes
.
MemoryViewSliceTypeNode
):
# reverse order to avoid having to write "(const int)[:]"
base_type
.
base_type_node
=
Nodes
.
CConstTypeNode
(
pos
,
base_type
=
base_type
.
base_type_node
)
return
base_type
return
Nodes
.
CConstTypeNode
(
pos
,
base_type
=
base_type
)
if
looking_at_base_type
(
s
):
#print "p_c_simple_base_type: looking_at_base_type at", s.position()
is_basic
=
1
...
...
Cython/Compiler/PyrexTypes.py
View file @
9ca6532b
...
...
@@ -316,6 +316,21 @@ class PyrexType(BaseType):
def
needs_nonecheck
(
self
):
return
0
def
_assign_from_py_code
(
self
,
source_code
,
result_code
,
error_pos
,
code
,
from_py_function
=
None
,
error_condition
=
None
,
extra_args
=
None
):
args
=
', '
+
', '
.
join
(
'%s'
%
arg
for
arg
in
extra_args
)
if
extra_args
else
''
convert_call
=
"%s(%s%s)"
%
(
from_py_function
or
self
.
from_py_function
,
source_code
,
args
,
)
if
self
.
is_enum
:
convert_call
=
typecast
(
self
,
c_long_type
,
convert_call
)
return
'%s = %s; %s'
%
(
result_code
,
convert_call
,
code
.
error_goto_if
(
error_condition
or
self
.
error_condition
(
result_code
),
error_pos
))
def
public_decl
(
base_code
,
dll_linkage
):
if
dll_linkage
:
...
...
@@ -493,12 +508,11 @@ class CTypedefType(BaseType):
def
from_py_call_code
(
self
,
source_code
,
result_code
,
error_pos
,
code
,
from_py_function
=
None
,
error_condition
=
None
):
if
from_py_function
is
None
:
from_py_function
=
self
.
from_py_function
if
error_condition
is
None
:
error_condition
=
self
.
error_condition
(
result_code
)
return
self
.
typedef_base_type
.
from_py_call_code
(
source_code
,
result_code
,
error_pos
,
code
,
from_py_function
,
error_condition
)
source_code
,
result_code
,
error_pos
,
code
,
from_py_function
or
self
.
from_py_function
,
error_condition
or
self
.
error_condition
(
result_code
)
)
def
overflow_check_binop
(
self
,
binop
,
env
,
const_rhs
=
False
):
env
.
use_utility_code
(
UtilityCode
.
load
(
"Common"
,
"Overflow.c"
))
...
...
@@ -621,6 +635,7 @@ class MemoryViewSliceType(PyrexType):
def
same_as_resolved_type
(
self
,
other_type
):
return
((
other_type
.
is_memoryviewslice
and
self
.
writable_needed
==
other_type
.
writable_needed
and
self
.
dtype
.
same_as
(
other_type
.
dtype
)
and
self
.
axes
==
other_type
.
axes
)
or
other_type
is
error_type
)
...
...
@@ -767,7 +782,18 @@ class MemoryViewSliceType(PyrexType):
src
=
self
if
src
.
dtype
!=
dst
.
dtype
:
if
self
.
writable_needed
and
not
dst
.
writable_needed
:
return
False
src_dtype
,
dst_dtype
=
src
.
dtype
,
dst
.
dtype
if
dst_dtype
.
is_const
:
# Requesting read-only views is always ok => consider only the non-const base type.
dst_dtype
=
dst_dtype
.
const_base_type
if
src_dtype
.
is_const
:
# When assigning between read-only views, compare only the non-const base types.
src_dtype
=
src_dtype
.
const_base_type
if
src_dtype
!=
dst_dtype
:
return
False
if
src
.
ndim
!=
dst
.
ndim
:
...
...
@@ -885,11 +911,12 @@ class MemoryViewSliceType(PyrexType):
def
from_py_call_code
(
self
,
source_code
,
result_code
,
error_pos
,
code
,
from_py_function
=
None
,
error_condition
=
None
):
return
'%s = %s(%s); %s'
%
(
result_code
,
from_py_function
or
self
.
from_py_function
,
source_code
,
code
.
error_goto_if
(
error_condition
or
self
.
error_condition
(
result_code
),
error_pos
))
# NOTE: auto-detection of readonly buffers is disabled:
# writable = self.writable_needed or not self.dtype.is_const
writable
=
not
self
.
dtype
.
is_const
return
self
.
_assign_from_py_code
(
source_code
,
result_code
,
error_pos
,
code
,
from_py_function
,
error_condition
,
extra_args
=
[
'PyBUF_WRITABLE'
if
writable
else
'0'
])
def
create_to_py_utility_code
(
self
,
env
):
self
.
_dtype_to_py_func
,
self
.
_dtype_from_py_func
=
self
.
dtype_object_conversion_funcs
(
env
)
...
...
@@ -917,25 +944,29 @@ class MemoryViewSliceType(PyrexType):
if
self
.
dtype
.
is_pyobject
:
utility_name
=
"MemviewObjectToObject"
else
:
to_py
=
self
.
dtype
.
create_to_py_utility_code
(
env
)
from_py
=
self
.
dtype
.
create_from_py_utility_code
(
env
)
if
not
(
to_py
or
from_py
):
return
"NULL"
,
"NULL"
self
.
dtype
.
create_to_py_utility_code
(
env
)
to_py_function
=
self
.
dtype
.
to_py_function
if
not
self
.
dtype
.
to_py_function
:
get_function
=
"NULL"
from_py_function
=
None
if
not
self
.
dtype
.
is_const
:
self
.
dtype
.
create_from_py_utility_code
(
env
)
from_py_function
=
self
.
dtype
.
from_py_function
if
not
self
.
dtype
.
from_py_function
:
if
not
(
to_py_function
or
from_py_function
):
return
"NULL"
,
"NULL"
if
not
to_py_function
:
get_function
=
"NULL"
if
not
from_py_function
:
set_function
=
"NULL"
utility_name
=
"MemviewDtypeToObject"
error_condition
=
(
self
.
dtype
.
error_condition
(
'value'
)
or
'PyErr_Occurred()'
)
context
.
update
(
to_py_function
=
self
.
dtype
.
to_py_function
,
from_py_function
=
self
.
dtype
.
from_py_function
,
dtype
=
self
.
dtype
.
empty_declaration_code
(),
error_condition
=
error_condition
,
to_py_function
=
to_py_function
,
from_py_function
=
from_py_function
,
dtype
=
self
.
dtype
.
empty_declaration_code
(),
error_condition
=
error_condition
,
)
utility
=
TempitaUtilityCode
.
load_cached
(
...
...
@@ -1470,11 +1501,9 @@ class CType(PyrexType):
def
from_py_call_code
(
self
,
source_code
,
result_code
,
error_pos
,
code
,
from_py_function
=
None
,
error_condition
=
None
):
return
'%s = %s(%s); %s'
%
(
result_code
,
from_py_function
or
self
.
from_py_function
,
source_code
,
code
.
error_goto_if
(
error_condition
or
self
.
error_condition
(
result_code
),
error_pos
))
return
self
.
_assign_from_py_code
(
source_code
,
result_code
,
error_pos
,
code
,
from_py_function
,
error_condition
)
class
PythranExpr
(
CType
):
...
...
@@ -2438,6 +2467,7 @@ class CArrayType(CPointerBaseType):
def
from_py_call_code
(
self
,
source_code
,
result_code
,
error_pos
,
code
,
from_py_function
=
None
,
error_condition
=
None
):
assert
not
error_condition
,
'%s: %s'
%
(
error_pos
,
error_condition
)
call_code
=
"%s(%s, %s, %s)"
%
(
from_py_function
or
self
.
from_py_function
,
source_code
,
result_code
,
self
.
size
)
...
...
@@ -3879,16 +3909,6 @@ class CEnumType(CIntLike, CType):
self
.
name
,
self
.
cname
,
self
.
typedef_flag
,
namespace
)
return
self
def
from_py_call_code
(
self
,
source_code
,
result_code
,
error_pos
,
code
,
from_py_function
=
None
,
error_condition
=
None
):
rhs
=
"%s(%s)"
%
(
from_py_function
or
self
.
from_py_function
,
source_code
)
return
'%s = %s;%s'
%
(
result_code
,
typecast
(
self
,
c_long_type
,
rhs
),
' %s'
%
code
.
error_goto_if
(
error_condition
or
self
.
error_condition
(
result_code
),
error_pos
))
def
create_type_wrapper
(
self
,
env
):
from
.UtilityCode
import
CythonUtilityCode
env
.
use_utility_code
(
CythonUtilityCode
.
load
(
...
...
Cython/Utility/MemoryView.pyx
View file @
9ca6532b
...
...
@@ -65,6 +65,7 @@ cdef extern from *:
PyBUF_STRIDES
PyBUF_INDIRECT
PyBUF_RECORDS
PyBUF_RECORDS_RO
ctypedef
struct
__Pyx_TypeInfo
:
pass
...
...
@@ -408,6 +409,9 @@ cdef class memoryview(object):
return
self
.
convert_item_to_object
(
itemp
)
def
__setitem__
(
memoryview
self
,
object
index
,
object
value
):
if
self
.
view
.
readonly
:
raise
TypeError
(
"Cannot assign to read-only memoryview"
)
have_slices
,
index
=
_unellipsify
(
index
,
self
.
view
.
ndim
)
if
have_slices
:
...
...
@@ -507,6 +511,9 @@ cdef class memoryview(object):
@
cname
(
'getbuffer'
)
def
__getbuffer__
(
self
,
Py_buffer
*
info
,
int
flags
):
if
flags
&
PyBUF_WRITABLE
and
self
.
view
.
readonly
:
raise
ValueError
(
"Cannot create writable memory view from read-only memoryview"
)
if
flags
&
PyBUF_STRIDES
:
info
.
shape
=
self
.
view
.
shape
else
:
...
...
@@ -531,7 +538,7 @@ cdef class memoryview(object):
info
.
ndim
=
self
.
view
.
ndim
info
.
itemsize
=
self
.
view
.
itemsize
info
.
len
=
self
.
view
.
len
info
.
readonly
=
0
info
.
readonly
=
self
.
view
.
readonly
info
.
obj
=
self
__pyx_getbuffer
=
capsule
(
<
void
*>
&
__pyx_memoryview_getbuffer
,
"getbuffer(obj, view, flags)"
)
...
...
@@ -1012,7 +1019,10 @@ cdef memoryview_fromslice({{memviewslice_name}} memviewslice,
(
<
__pyx_buffer
*>
&
result
.
view
).
obj
=
Py_None
Py_INCREF
(
Py_None
)
if
(
<
memoryview
>
memviewslice
.
memview
).
flags
&
PyBUF_WRITABLE
:
result
.
flags
=
PyBUF_RECORDS
else
:
result
.
flags
=
PyBUF_RECORDS_RO
result
.
view
.
shape
=
<
Py_ssize_t
*>
result
.
from_slice
.
shape
result
.
view
.
strides
=
<
Py_ssize_t
*>
result
.
from_slice
.
strides
...
...
Cython/Utility/MemoryView_C.c
View file @
9ca6532b
...
...
@@ -82,7 +82,7 @@ typedef volatile __pyx_atomic_int_type __pyx_atomic_int;
/////////////// ObjectToMemviewSlice.proto ///////////////
static
CYTHON_INLINE
{{
memviewslice_name
}}
{{
funcname
}}(
PyObject
*
);
static
CYTHON_INLINE
{{
memviewslice_name
}}
{{
funcname
}}(
PyObject
*
,
int
writable_flag
);
////////// MemviewSliceInit.proto //////////
...
...
@@ -127,7 +127,7 @@ static CYTHON_INLINE char *__pyx_memviewslice_index_full(
/////////////// ObjectToMemviewSlice ///////////////
//@requires: MemviewSliceValidateAndInit
static
CYTHON_INLINE
{{
memviewslice_name
}}
{{
funcname
}}(
PyObject
*
obj
)
{
static
CYTHON_INLINE
{{
memviewslice_name
}}
{{
funcname
}}(
PyObject
*
obj
,
int
writable_flag
)
{
{{
memviewslice_name
}}
result
=
{{
memslice_init
}};
__Pyx_BufFmt_StackElem
stack
[{{
struct_nesting_depth
}}];
int
axes_specs
[]
=
{
{{
axes_specs
}}
};
...
...
@@ -140,7 +140,7 @@ static CYTHON_INLINE {{memviewslice_name}} {{funcname}}(PyObject *obj) {
}
retcode
=
__Pyx_ValidateAndInit_memviewslice
(
axes_specs
,
{{
c_or_f_flag
}},
{{
buf_flag
}},
{{
ndim
}},
{{
buf_flag
}}
|
writable_flag
,
{{
ndim
}},
&
{{
dtype_typeinfo
}},
stack
,
&
result
,
obj
);
...
...
docs/src/userguide/memoryviews.rst
View file @
9ca6532b
...
...
@@ -227,6 +227,33 @@ As for NumPy, new axes can be introduced by indexing an array with ``None`` ::
One may mix new axis indexing with all other forms of indexing and slicing.
See also an example_.
Read-only views
---------------
Since Cython 0.28, the memoryview item type can be declared as ``const`` to
support read-only buffers as input::
cdef const double[:] myslice # const item type => read-only view
a = np.linspace(0, 10, num=50)
a.setflags(write=False)
myslice = a
Note that this does not *require* the input buffer to be read-only::
a = np.linspace(0, 10, num=50)
myslice = a # read-only view of a writable buffer
Writable buffers are still accepted by ``const`` views, but read-only
buffers are not accepted for non-const, writable views::
cdef double[:] myslice # a normal read/write memory view
a = np.linspace(0, 10, num=50)
a.setflags(write=False)
myslice = a # ERROR: requesting writable memory view from read-only buffer!
Comparison to the old buffer support
====================================
...
...
tests/buffers/bufaccess.pyx
View file @
9ca6532b
...
...
@@ -599,7 +599,7 @@ def readonly(obj):
acquired R
25
released R
>>> [str(x) for x in R.rec
ie
ved_flags] # Works in both py2 and py3
>>> [str(x) for x in R.rec
ei
ved_flags] # Works in both py2 and py3
['FORMAT', 'INDIRECT', 'ND', 'STRIDES']
"""
cdef
object
[
unsigned
short
int
,
ndim
=
3
]
buf
=
obj
...
...
@@ -612,7 +612,7 @@ def writable(obj):
>>> writable(R)
acquired R
released R
>>> [str(x) for x in R.rec
ie
ved_flags] # Py2/3
>>> [str(x) for x in R.rec
ei
ved_flags] # Py2/3
['FORMAT', 'INDIRECT', 'ND', 'STRIDES', 'WRITABLE']
"""
cdef
object
[
unsigned
short
int
,
ndim
=
3
]
buf
=
obj
...
...
@@ -626,7 +626,7 @@ def strided(object[int, ndim=1, mode='strided'] buf):
acquired A
released A
2
>>> [str(x) for x in A.rec
ie
ved_flags] # Py2/3
>>> [str(x) for x in A.rec
ei
ved_flags] # Py2/3
['FORMAT', 'ND', 'STRIDES']
Check that the suboffsets were patched back prior to release.
...
...
@@ -641,7 +641,7 @@ def c_contig(object[int, ndim=1, mode='c'] buf):
>>> A = IntMockBuffer(None, range(4))
>>> c_contig(A)
2
>>> [str(x) for x in A.rec
ie
ved_flags]
>>> [str(x) for x in A.rec
ei
ved_flags]
['FORMAT', 'ND', 'STRIDES', 'C_CONTIGUOUS']
"""
return
buf
[
2
]
...
...
@@ -654,7 +654,7 @@ def c_contig_2d(object[int, ndim=2, mode='c'] buf):
>>> A = IntMockBuffer(None, range(12), shape=(3,4))
>>> c_contig_2d(A)
7
>>> [str(x) for x in A.rec
ie
ved_flags]
>>> [str(x) for x in A.rec
ei
ved_flags]
['FORMAT', 'ND', 'STRIDES', 'C_CONTIGUOUS']
"""
return
buf
[
1
,
3
]
...
...
@@ -665,7 +665,7 @@ def f_contig(object[int, ndim=1, mode='fortran'] buf):
>>> A = IntMockBuffer(None, range(4))
>>> f_contig(A)
2
>>> [str(x) for x in A.rec
ie
ved_flags]
>>> [str(x) for x in A.rec
ei
ved_flags]
['FORMAT', 'ND', 'STRIDES', 'F_CONTIGUOUS']
"""
return
buf
[
2
]
...
...
@@ -678,7 +678,7 @@ def f_contig_2d(object[int, ndim=2, mode='fortran'] buf):
>>> A = IntMockBuffer(None, range(12), shape=(4,3), strides=(1, 4))
>>> f_contig_2d(A)
7
>>> [str(x) for x in A.rec
ie
ved_flags]
>>> [str(x) for x in A.rec
ei
ved_flags]
['FORMAT', 'ND', 'STRIDES', 'F_CONTIGUOUS']
"""
return
buf
[
3
,
1
]
...
...
@@ -1103,7 +1103,7 @@ def bufdefaults1(IntStridedMockBuffer[int, ndim=1] buf):
>>> bufdefaults1(A)
acquired A
released A
>>> [str(x) for x in A.rec
ie
ved_flags]
>>> [str(x) for x in A.rec
ei
ved_flags]
['FORMAT', 'ND', 'STRIDES']
"""
pass
...
...
tests/buffers/mockbuffers.pxi
View file @
9ca6532b
...
...
@@ -18,16 +18,17 @@ cdef class MockBuffer:
cdef
object
format
,
offset
cdef
void
*
buffer
cdef
Py_ssize_t
len
,
itemsize
cdef
int
ndim
cdef
Py_ssize_t
*
strides
cdef
Py_ssize_t
*
shape
cdef
Py_ssize_t
*
suboffsets
cdef
object
label
,
log
cdef
int
ndim
cdef
bint
writable
cdef
readonly
object
rec
ie
ved_flags
,
release_ok
cdef
readonly
object
rec
ei
ved_flags
,
release_ok
cdef
public
object
fail
def
__init__
(
self
,
label
,
data
,
shape
=
None
,
strides
=
None
,
format
=
None
,
offset
=
0
):
def
__init__
(
self
,
label
,
data
,
shape
=
None
,
strides
=
None
,
format
=
None
,
writable
=
True
,
offset
=
0
):
# It is important not to store references to data after the constructor
# as refcounting is checked on object buffers.
self
.
label
=
label
...
...
@@ -35,6 +36,7 @@ cdef class MockBuffer:
self
.
log
=
""
self
.
offset
=
offset
self
.
itemsize
=
self
.
get_itemsize
()
self
.
writable
=
writable
if
format
is
None
:
format
=
self
.
get_default_format
()
if
shape
is
None
:
shape
=
(
len
(
data
),)
if
strides
is
None
:
...
...
@@ -127,16 +129,19 @@ cdef class MockBuffer:
if
self
.
fail
:
raise
ValueError
(
"Failing on purpose"
)
self
.
rec
ie
ved_flags
=
[]
self
.
rec
ei
ved_flags
=
[]
cdef
int
value
for
name
,
value
in
available_flags
:
if
(
value
&
flags
)
==
value
:
self
.
recieved_flags
.
append
(
name
)
self
.
received_flags
.
append
(
name
)
if
flags
&
cpython
.
buffer
.
PyBUF_WRITABLE
and
not
self
.
writable
:
raise
BufferError
(
"Writable buffer requested from read-only mock: %s"
%
' | '
.
join
(
self
.
received_flags
))
buffer
.
buf
=
<
void
*>
(
<
char
*>
self
.
buffer
+
(
<
int
>
self
.
offset
*
self
.
itemsize
))
buffer
.
obj
=
self
buffer
.
len
=
self
.
len
buffer
.
readonly
=
0
buffer
.
readonly
=
not
self
.
writable
buffer
.
format
=
<
char
*>
self
.
format
buffer
.
ndim
=
self
.
ndim
buffer
.
shape
=
self
.
shape
...
...
tests/errors/e_arrayassign.pyx
View file @
9ca6532b
# mode: error
# cython: auto_pickle=False
ctypedef
int
[
1
]
int_array
ctypedef
int
[
2
]
int_array2
...
...
@@ -30,6 +31,6 @@ d = z # not an error
_ERRORS
=
u"""
2
0
:0: Assignment to slice of wrong length, expected 2, got 1
2
1
:0: Assignment to slice of wrong length, expected 1, got 2
2
1
:0: Assignment to slice of wrong length, expected 2, got 1
2
2
:0: Assignment to slice of wrong length, expected 1, got 2
"""
tests/memoryview/memoryview.pyx
View file @
9ca6532b
...
...
@@ -420,7 +420,7 @@ def writable(unsigned short int[:, :, :] mslice):
>>> writable(R)
acquired R
released R
>>> [str(x) for x in R.rec
ie
ved_flags] # Py2/3
>>> [str(x) for x in R.rec
ei
ved_flags] # Py2/3
['FORMAT', 'ND', 'STRIDES', 'WRITABLE']
"""
buf
=
mslice
...
...
tests/memoryview/memslice.pyx
View file @
9ca6532b
...
...
@@ -279,8 +279,8 @@ def cascaded_buffer_assignment(obj):
@
testcase
def
tuple_buffer_assignment1
(
a
,
b
):
"""
>>> A = IntMockBuffer("A", range(6))
>>> B = IntMockBuffer("B", range(6))
>>> A = IntMockBuffer("A", range(6))
# , writable=False)
>>> B = IntMockBuffer("B", range(6))
# , writable=False)
>>> tuple_buffer_assignment1(A, B)
acquired A
acquired B
...
...
@@ -293,8 +293,8 @@ def tuple_buffer_assignment1(a, b):
@
testcase
def
tuple_buffer_assignment2
(
tup
):
"""
>>> A = IntMockBuffer("A", range(6))
>>> B = IntMockBuffer("B", range(6))
>>> A = IntMockBuffer("A", range(6))
# , writable=False)
>>> B = IntMockBuffer("B", range(6))
# , writable=False)
>>> tuple_buffer_assignment2((A, B))
acquired A
acquired B
...
...
@@ -312,7 +312,7 @@ def explicitly_release_buffer():
released A
After release
"""
cdef
int
[:]
x
=
IntMockBuffer
(
"A"
,
range
(
10
))
cdef
int
[:]
x
=
IntMockBuffer
(
"A"
,
range
(
10
))
# , writable=False)
del
x
print
"After release"
...
...
@@ -358,7 +358,7 @@ def get_int_2d(int[:, :] buf, int i, int j):
def
get_int_2d_uintindex
(
int
[:,
:]
buf
,
unsigned
int
i
,
unsigned
int
j
):
"""
Unsigned indexing:
>>> C = IntMockBuffer("C", range(6), (2,3))
>>> C = IntMockBuffer("C", range(6), (2,3))
# , writable=False)
>>> get_int_2d_uintindex(C, 0, 0)
acquired C
released C
...
...
@@ -422,6 +422,10 @@ def set_int_2d(int[:, :] buf, int i, int j, int value):
...
IndexError: Out of bounds on buffer access (axis 1)
>>> C = IntMockBuffer("C", range(6), (2,3), writable=False)
>>> set_int_2d(C, -2, -3, 9)
Traceback (most recent call last):
BufferError: Writable buffer requested from read-only mock: FORMAT | ND | STRIDES | WRITABLE
"""
buf
[
i
,
j
]
=
value
...
...
@@ -588,11 +592,11 @@ def char_index_vars(int[:, :] buf, char i, char j, int value):
@
testcase
def
list_comprehension
(
int
[:]
buf
,
len
):
"""
>>> list_comprehension(IntMockBuffer(None, [1,2,3]), 3)
>>> list_comprehension(IntMockBuffer(None, [1,2,3]), 3)
# , writable=False), 3)
1|2|3
"""
cdef
int
i
print
u"|"
.
join
([
unicode
(
buf
[
i
])
for
i
in
range
(
len
)])
print
"|"
.
join
([
str
(
buf
[
i
])
for
i
in
range
(
len
)])
@
testcase
@
cython
.
wraparound
(
False
)
...
...
@@ -600,7 +604,7 @@ def wraparound_directive(int[:] buf, int pos_idx, int neg_idx):
"""
Again, the most interesting thing here is to inspect the C source.
>>> A = IntMockBuffer(None, range(4))
>>> A = IntMockBuffer(None, range(4))
# , writable=False)
>>> wraparound_directive(A, 2, -1)
5
>>> wraparound_directive(A, -1, 2)
...
...
@@ -625,22 +629,22 @@ def writable(obj):
>>> writable(R)
acquired R
released R
>>> [str(x) for x in R.rec
ie
ved_flags] # Py2/3
>>> [str(x) for x in R.rec
ei
ved_flags] # Py2/3
['FORMAT', 'ND', 'STRIDES', 'WRITABLE']
"""
cdef
unsigned
short
int
[:,
:,
:]
buf
=
obj
buf
[
2
,
2
,
1
]
=
23
@
testcase
def
strided
(
int
[:]
buf
):
def
strided
(
const
int
[:]
buf
):
"""
>>> A = IntMockBuffer("A", range(4))
>>> A = IntMockBuffer("A", range(4)
, writable=False
)
>>> strided(A)
acquired A
released A
2
>>> [str(x) for x in A.rec
ie
ved_flags] # Py2/3
['FORMAT', 'ND', 'STRIDES'
, 'WRITABLE'
]
>>> [str(x) for x in A.rec
ei
ved_flags] # Py2/3
['FORMAT', 'ND', 'STRIDES']
Check that the suboffsets were patched back prior to release.
>>> A.release_ok
...
...
@@ -649,13 +653,13 @@ def strided(int[:] buf):
return
buf
[
2
]
@
testcase
def
c_contig
(
int
[::
1
]
buf
):
def
c_contig
(
const
int
[::
1
]
buf
):
"""
>>> A = IntMockBuffer(None, range(4))
>>> A = IntMockBuffer(None, range(4)
, writable=False
)
>>> c_contig(A)
2
>>> [str(x) for x in A.rec
ie
ved_flags]
['FORMAT', 'ND', 'STRIDES', 'C_CONTIGUOUS'
, 'WRITABLE'
]
>>> [str(x) for x in A.rec
ei
ved_flags]
['FORMAT', 'ND', 'STRIDES', 'C_CONTIGUOUS']
"""
return
buf
[
2
]
...
...
@@ -664,10 +668,10 @@ def c_contig_2d(int[:, ::1] buf):
"""
Multi-dim has separate implementation
>>> A = IntMockBuffer(None, range(12), shape=(3,4))
>>> A = IntMockBuffer(None, range(12), shape=(3,4))
# , writable=False)
>>> c_contig_2d(A)
7
>>> [str(x) for x in A.rec
ie
ved_flags]
>>> [str(x) for x in A.rec
ei
ved_flags]
['FORMAT', 'ND', 'STRIDES', 'C_CONTIGUOUS', 'WRITABLE']
"""
return
buf
[
1
,
3
]
...
...
@@ -675,10 +679,10 @@ def c_contig_2d(int[:, ::1] buf):
@
testcase
def
f_contig
(
int
[::
1
,
:]
buf
):
"""
>>> A = IntMockBuffer(None, range(4), shape=(2, 2), strides=(1, 2))
>>> A = IntMockBuffer(None, range(4), shape=(2, 2), strides=(1, 2))
# , writable=False)
>>> f_contig(A)
2
>>> [str(x) for x in A.rec
ie
ved_flags]
>>> [str(x) for x in A.rec
ei
ved_flags]
['FORMAT', 'ND', 'STRIDES', 'F_CONTIGUOUS', 'WRITABLE']
"""
return
buf
[
0
,
1
]
...
...
@@ -688,10 +692,10 @@ def f_contig_2d(int[::1, :] buf):
"""
Must set up strides manually to ensure Fortran ordering.
>>> A = IntMockBuffer(None, range(12), shape=(4,3), strides=(1, 4))
>>> A = IntMockBuffer(None, range(12), shape=(4,3), strides=(1, 4))
# , writable=False)
>>> f_contig_2d(A)
7
>>> [str(x) for x in A.rec
ie
ved_flags]
>>> [str(x) for x in A.rec
ei
ved_flags]
['FORMAT', 'ND', 'STRIDES', 'F_CONTIGUOUS', 'WRITABLE']
"""
return
buf
[
3
,
1
]
...
...
@@ -711,9 +715,9 @@ def generic(int[::view.generic, ::view.generic] buf1,
11
released A
released B
>>> [str(x) for x in A.rec
ie
ved_flags]
>>> [str(x) for x in A.rec
ei
ved_flags]
['FORMAT', 'INDIRECT', 'ND', 'STRIDES', 'WRITABLE']
>>> [str(x) for x in B.rec
ie
ved_flags]
>>> [str(x) for x in B.rec
ei
ved_flags]
['FORMAT', 'INDIRECT', 'ND', 'STRIDES', 'WRITABLE']
"""
print
buf1
[
1
,
1
]
...
...
@@ -741,9 +745,9 @@ def generic(int[::view.generic, ::view.generic] buf1,
# 11
# released A
# released B
# >>> [str(x) for x in A.rec
ie
ved_flags]
# >>> [str(x) for x in A.rec
ei
ved_flags]
# ['FORMAT', 'INDIRECT', 'ND', 'STRIDES', 'WRITABLE']
# >>> [str(x) for x in B.rec
ie
ved_flags]
# >>> [str(x) for x in B.rec
ei
ved_flags]
# ['FORMAT', 'INDIRECT', 'ND', 'STRIDES', 'WRITABLE']
# """
# print buf1[1, 1]
...
...
@@ -771,9 +775,9 @@ def indirect_strided_and_contig(
11
released A
released B
>>> [str(x) for x in A.rec
ie
ved_flags]
>>> [str(x) for x in A.rec
ei
ved_flags]
['FORMAT', 'INDIRECT', 'ND', 'STRIDES', 'WRITABLE']
>>> [str(x) for x in B.rec
ie
ved_flags]
>>> [str(x) for x in B.rec
ei
ved_flags]
['FORMAT', 'INDIRECT', 'ND', 'STRIDES', 'WRITABLE']
"""
print
buf1
[
1
,
1
]
...
...
@@ -802,9 +806,9 @@ def indirect_contig(
11
released A
released B
>>> [str(x) for x in A.rec
ie
ved_flags]
>>> [str(x) for x in A.rec
ei
ved_flags]
['FORMAT', 'INDIRECT', 'ND', 'STRIDES', 'WRITABLE']
>>> [str(x) for x in B.rec
ie
ved_flags]
>>> [str(x) for x in B.rec
ei
ved_flags]
['FORMAT', 'INDIRECT', 'ND', 'STRIDES', 'WRITABLE']
"""
print
buf1
[
1
,
1
]
...
...
@@ -827,7 +831,7 @@ def indirect_contig(
@
testcase
def
safe_get
(
int
[:]
buf
,
int
idx
):
"""
>>> A = IntMockBuffer(None, range(10), shape=(3,), offset=5)
>>> A = IntMockBuffer(None, range(10), shape=(3,), offset=5)
# , writable=False)
Validate our testing buffer...
>>> safe_get(A, 0)
...
...
@@ -857,7 +861,7 @@ def safe_get(int[:] buf, int idx):
def
unsafe_get
(
int
[:]
buf
,
int
idx
):
"""
Access outside of the area the buffer publishes.
>>> A = IntMockBuffer(None, range(10), shape=(3,), offset=5)
>>> A = IntMockBuffer(None, range(10), shape=(3,), offset=5)
# , writable=False)
>>> unsafe_get(A, -4)
4
>>> unsafe_get(A, -5)
...
...
@@ -870,7 +874,7 @@ def unsafe_get(int[:] buf, int idx):
@
testcase
def
mixed_get
(
int
[:]
buf
,
int
unsafe_idx
,
int
safe_idx
):
"""
>>> A = IntMockBuffer(None, range(10), shape=(3,), offset=5)
>>> A = IntMockBuffer(None, range(10), shape=(3,), offset=5)
# , writable=False)
>>> mixed_get(A, -4, 0)
(4, 5)
>>> mixed_get(A, 0, -4)
...
...
@@ -902,12 +906,12 @@ def printbuf_int_2d(o, shape):
"""
Strided:
>>> printbuf_int_2d(IntMockBuffer("A", range(6), (2,3)), (2,3))
>>> printbuf_int_2d(IntMockBuffer("A", range(6), (2,3)
, writable=False
), (2,3))
acquired A
0 1 2 END
3 4 5 END
released A
>>> printbuf_int_2d(IntMockBuffer("A", range(100), (3,3), strides=(20,5)), (3,3))
>>> printbuf_int_2d(IntMockBuffer("A", range(100), (3,3), strides=(20,5)
, writable=False
), (3,3))
acquired A
0 5 10 END
20 25 30 END
...
...
@@ -915,14 +919,14 @@ def printbuf_int_2d(o, shape):
released A
Indirect:
>>> printbuf_int_2d(IntMockBuffer("A", [[1,2],[3,4]]), (2,2))
>>> printbuf_int_2d(IntMockBuffer("A", [[1,2],[3,4]]
, writable=False
), (2,2))
acquired A
1 2 END
3 4 END
released A
"""
# should make shape builtin
cdef
int
[::
view
.
generic
,
::
view
.
generic
]
buf
cdef
const
int
[::
view
.
generic
,
::
view
.
generic
]
buf
buf
=
o
cdef
int
i
,
j
for
i
in
range
(
shape
[
0
]):
...
...
@@ -933,14 +937,14 @@ def printbuf_int_2d(o, shape):
@
testcase
def
printbuf_float
(
o
,
shape
):
"""
>>> printbuf_float(FloatMockBuffer("F", [1.0, 1.25, 0.75, 1.0]), (4,))
>>> printbuf_float(FloatMockBuffer("F", [1.0, 1.25, 0.75, 1.0]
, writable=False
), (4,))
acquired F
1.0 1.25 0.75 1.0 END
released F
"""
# should make shape builtin
cdef
float
[:]
buf
cdef
const
float
[:]
buf
buf
=
o
cdef
int
i
,
j
for
i
in
range
(
shape
[
0
]):
...
...
@@ -982,9 +986,9 @@ ctypedef td_h_short td_h_cy_short
@
testcase
def
printbuf_td_cy_int
(
td_cy_int
[:]
buf
,
shape
):
"""
>>> printbuf_td_cy_int(IntMockBuffer(None, range(3)), (3,))
>>> printbuf_td_cy_int(IntMockBuffer(None, range(3)), (3,))
# , writable=False), (3,))
0 1 2 END
>>> printbuf_td_cy_int(ShortMockBuffer(None, range(3)), (3,))
>>> printbuf_td_cy_int(ShortMockBuffer(None, range(3)), (3,))
# , writable=False), (3,))
Traceback (most recent call last):
...
ValueError: Buffer dtype mismatch, expected 'td_cy_int' but got 'short'
...
...
@@ -997,9 +1001,9 @@ def printbuf_td_cy_int(td_cy_int[:] buf, shape):
@
testcase
def
printbuf_td_h_short
(
td_h_short
[:]
buf
,
shape
):
"""
>>> printbuf_td_h_short(ShortMockBuffer(None, range(3)), (3,))
>>> printbuf_td_h_short(ShortMockBuffer(None, range(3)), (3,))
# , writable=False), (3,))
0 1 2 END
>>> printbuf_td_h_short(IntMockBuffer(None, range(3)), (3,))
>>> printbuf_td_h_short(IntMockBuffer(None, range(3)), (3,))
# , writable=False), (3,))
Traceback (most recent call last):
...
ValueError: Buffer dtype mismatch, expected 'td_h_short' but got 'int'
...
...
@@ -1010,14 +1014,14 @@ def printbuf_td_h_short(td_h_short[:] buf, shape):
print
'END'
@
testcase
def
printbuf_td_h_cy_short
(
td_h_cy_short
[:]
buf
,
shape
):
def
printbuf_td_h_cy_short
(
const
td_h_cy_short
[:]
buf
,
shape
):
"""
>>> printbuf_td_h_cy_short(ShortMockBuffer(None, range(3)), (3,))
>>> printbuf_td_h_cy_short(ShortMockBuffer(None, range(3)
, writable=False
), (3,))
0 1 2 END
>>> printbuf_td_h_cy_short(IntMockBuffer(None, range(3)), (3,))
>>> printbuf_td_h_cy_short(IntMockBuffer(None, range(3)
, writable=False
), (3,))
Traceback (most recent call last):
...
ValueError: Buffer dtype mismatch, expected 'td_h_cy_short' but got 'int'
ValueError: Buffer dtype mismatch, expected '
const
td_h_cy_short' but got 'int'
"""
cdef
int
i
for
i
in
range
(
shape
[
0
]):
...
...
@@ -1025,14 +1029,14 @@ def printbuf_td_h_cy_short(td_h_cy_short[:] buf, shape):
print
'END'
@
testcase
def
printbuf_td_h_ushort
(
td_h_ushort
[:]
buf
,
shape
):
def
printbuf_td_h_ushort
(
const
td_h_ushort
[:]
buf
,
shape
):
"""
>>> printbuf_td_h_ushort(UnsignedShortMockBuffer(None, range(3)), (3,))
>>> printbuf_td_h_ushort(UnsignedShortMockBuffer(None, range(3)
, writable=False
), (3,))
0 1 2 END
>>> printbuf_td_h_ushort(ShortMockBuffer(None, range(3)), (3,))
>>> printbuf_td_h_ushort(ShortMockBuffer(None, range(3)
, writable=False
), (3,))
Traceback (most recent call last):
...
ValueError: Buffer dtype mismatch, expected 'td_h_ushort' but got 'short'
ValueError: Buffer dtype mismatch, expected '
const
td_h_ushort' but got 'short'
"""
cdef
int
i
for
i
in
range
(
shape
[
0
]):
...
...
@@ -1040,14 +1044,14 @@ def printbuf_td_h_ushort(td_h_ushort[:] buf, shape):
print
'END'
@
testcase
def
printbuf_td_h_double
(
td_h_double
[:]
buf
,
shape
):
def
printbuf_td_h_double
(
const
td_h_double
[:]
buf
,
shape
):
"""
>>> printbuf_td_h_double(DoubleMockBuffer(None, [0.25, 1, 3.125]), (3,))
>>> printbuf_td_h_double(DoubleMockBuffer(None, [0.25, 1, 3.125]
, writable=False
), (3,))
0.25 1.0 3.125 END
>>> printbuf_td_h_double(FloatMockBuffer(None, [0.25, 1, 3.125]), (3,))
>>> printbuf_td_h_double(FloatMockBuffer(None, [0.25, 1, 3.125]
, writable=False
), (3,))
Traceback (most recent call last):
...
ValueError: Buffer dtype mismatch, expected 'td_h_double' but got 'float'
ValueError: Buffer dtype mismatch, expected '
const
td_h_double' but got 'float'
"""
cdef
int
i
for
i
in
range
(
shape
[
0
]):
...
...
@@ -1079,7 +1083,7 @@ def printbuf_object(object[:] buf, shape):
>>> a, b, c = "globally_unique_string_23234123", {4:23}, [34,3]
>>> get_refcount(a), get_refcount(b), get_refcount(c)
(2, 2, 2)
>>> A = ObjectMockBuffer(None, [a, b, c])
>>> A = ObjectMockBuffer(None, [a, b, c])
# , writable=False)
>>> printbuf_object(A, (3,))
'globally_unique_string_23234123' 2
{4: 23} 2
...
...
@@ -1145,11 +1149,11 @@ def bufdefaults1(int[:] buf):
"strided" by defaults which should show
up in the flags.
>>> A = IntStridedMockBuffer("A", range(10))
>>> A = IntStridedMockBuffer("A", range(10))
# , writable=False)
>>> bufdefaults1(A)
acquired A
released A
>>> [str(x) for x in A.rec
ie
ved_flags]
>>> [str(x) for x in A.rec
ei
ved_flags]
['FORMAT', 'ND', 'STRIDES', 'WRITABLE']
"""
pass
...
...
@@ -1160,9 +1164,9 @@ def basic_struct(MyStruct[:] buf):
"""
See also buffmt.pyx
>>> basic_struct(MyStructMockBuffer(None, [(1, 2, 3, 4, 5)]))
>>> basic_struct(MyStructMockBuffer(None, [(1, 2, 3, 4, 5)]))
# , writable=False))
1 2 3 4 5
>>> basic_struct(MyStructMockBuffer(None, [(1, 2, 3, 4, 5)], format="ccqii"))
>>> basic_struct(MyStructMockBuffer(None, [(1, 2, 3, 4, 5)], format="ccqii"))
# , writable=False))
1 2 3 4 5
"""
print
buf
[
0
].
a
,
buf
[
0
].
b
,
buf
[
0
].
c
,
buf
[
0
].
d
,
buf
[
0
].
e
...
...
@@ -1172,9 +1176,9 @@ def nested_struct(NestedStruct[:] buf):
"""
See also buffmt.pyx
>>> nested_struct(NestedStructMockBuffer(None, [(1, 2, 3, 4, 5)]))
>>> nested_struct(NestedStructMockBuffer(None, [(1, 2, 3, 4, 5)]))
# , writable=False))
1 2 3 4 5
>>> nested_struct(NestedStructMockBuffer(None, [(1, 2, 3, 4, 5)], format="T{ii}T{2i}i"))
>>> nested_struct(NestedStructMockBuffer(None, [(1, 2, 3, 4, 5)], format="T{ii}T{2i}i"))
# , writable=False))
1 2 3 4 5
"""
print
buf
[
0
].
x
.
a
,
buf
[
0
].
x
.
b
,
buf
[
0
].
y
.
a
,
buf
[
0
].
y
.
b
,
buf
[
0
].
z
...
...
@@ -1184,11 +1188,11 @@ def packed_struct(PackedStruct[:] buf):
"""
See also buffmt.pyx
>>> packed_struct(PackedStructMockBuffer(None, [(1, 2)]))
>>> packed_struct(PackedStructMockBuffer(None, [(1, 2)]))
# , writable=False))
1 2
>>> packed_struct(PackedStructMockBuffer(None, [(1, 2)], format="T{c^i}"))
>>> packed_struct(PackedStructMockBuffer(None, [(1, 2)], format="T{c^i}"))
# , writable=False))
1 2
>>> packed_struct(PackedStructMockBuffer(None, [(1, 2)], format="T{c=i}"))
>>> packed_struct(PackedStructMockBuffer(None, [(1, 2)], format="T{c=i}"))
# , writable=False))
1 2
"""
...
...
@@ -1199,11 +1203,11 @@ def nested_packed_struct(NestedPackedStruct[:] buf):
"""
See also buffmt.pyx
>>> nested_packed_struct(NestedPackedStructMockBuffer(None, [(1, 2, 3, 4, 5)]))
>>> nested_packed_struct(NestedPackedStructMockBuffer(None, [(1, 2, 3, 4, 5)]))
# , writable=False))
1 2 3 4 5
>>> nested_packed_struct(NestedPackedStructMockBuffer(None, [(1, 2, 3, 4, 5)], format="ci^ci@i"))
>>> nested_packed_struct(NestedPackedStructMockBuffer(None, [(1, 2, 3, 4, 5)], format="ci^ci@i"))
# , writable=False))
1 2 3 4 5
>>> nested_packed_struct(NestedPackedStructMockBuffer(None, [(1, 2, 3, 4, 5)], format="^c@i^ci@i"))
>>> nested_packed_struct(NestedPackedStructMockBuffer(None, [(1, 2, 3, 4, 5)], format="^c@i^ci@i"))
# , writable=False))
1 2 3 4 5
"""
print
buf
[
0
].
a
,
buf
[
0
].
b
,
buf
[
0
].
sub
.
a
,
buf
[
0
].
sub
.
b
,
buf
[
0
].
c
...
...
@@ -1212,7 +1216,7 @@ def nested_packed_struct(NestedPackedStruct[:] buf):
@
testcase
def
complex_dtype
(
long
double
complex
[:]
buf
):
"""
>>> complex_dtype(LongComplexMockBuffer(None, [(0, -1)]))
>>> complex_dtype(LongComplexMockBuffer(None, [(0, -1)]))
# , writable=False))
-1j
"""
print
buf
[
0
]
...
...
@@ -1231,7 +1235,7 @@ def complex_struct_dtype(LongComplex[:] buf):
"""
Note that the format string is "Zg" rather than "2g", yet a struct
is accessed.
>>> complex_struct_dtype(LongComplexMockBuffer(None, [(0, -1)]))
>>> complex_struct_dtype(LongComplexMockBuffer(None, [(0, -1)]))
# , writable=False))
0.0 -1.0
"""
print
buf
[
0
].
real
,
buf
[
0
].
imag
...
...
@@ -1359,7 +1363,7 @@ def test_cdef_function2():
def
test_generic_slicing
(
arg
,
indirect
=
False
):
"""
Test simple slicing
>>> test_generic_slicing(IntMockBuffer("A", range(8 * 14 * 11), shape=(8, 14, 11)))
>>> test_generic_slicing(IntMockBuffer("A", range(8 * 14 * 11), shape=(8, 14, 11)))
# , writable=False))
acquired A
3 9 2
308 -11 1
...
...
@@ -1367,7 +1371,7 @@ def test_generic_slicing(arg, indirect=False):
released A
Test direct slicing, negative slice oob in dim 2
>>> test_generic_slicing(IntMockBuffer("A", range(1 * 2 * 3), shape=(1, 2, 3)))
>>> test_generic_slicing(IntMockBuffer("A", range(1 * 2 * 3), shape=(1, 2, 3)))
# , writable=False))
acquired A
0 0 2
12 -3 1
...
...
@@ -1375,13 +1379,13 @@ def test_generic_slicing(arg, indirect=False):
released A
Test indirect slicing
>>> test_generic_slicing(IntMockBuffer("A", shape_5_3_4_list, shape=(5, 3, 4)), indirect=True)
>>> test_generic_slicing(IntMockBuffer("A", shape_5_3_4_list, shape=(5, 3, 4)), indirect=True)
# , writable=False), indirect=True)
acquired A
2 0 2
0 1 -1
released A
>>> test_generic_slicing(IntMockBuffer("A", shape_9_14_21_list, shape=(9, 14, 21)), indirect=True)
>>> test_generic_slicing(IntMockBuffer("A", shape_9_14_21_list, shape=(9, 14, 21)), indirect=True)
# , writable=False), indirect=True)
acquired A
3 9 2
10 1 -1
...
...
@@ -1413,7 +1417,7 @@ def test_generic_slicing(arg, indirect=False):
def
test_indirect_slicing
(
arg
):
"""
Test indirect slicing
>>> test_indirect_slicing(IntMockBuffer("A", shape_5_3_4_list, shape=(5, 3, 4)))
>>> test_indirect_slicing(IntMockBuffer("A", shape_5_3_4_list, shape=(5, 3, 4)))
# , writable=False))
acquired A
5 3 2
0 0 -1
...
...
@@ -1428,7 +1432,7 @@ def test_indirect_slicing(arg):
58
released A
>>> test_indirect_slicing(IntMockBuffer("A", shape_9_14_21_list, shape=(9, 14, 21)))
>>> test_indirect_slicing(IntMockBuffer("A", shape_9_14_21_list, shape=(9, 14, 21)))
# , writable=False))
acquired A
5 14 3
0 16 -1
...
...
@@ -1553,7 +1557,7 @@ def test_direct_slicing(arg):
Fused types would be convenient to test this stuff!
Test simple slicing
>>> test_direct_slicing(IntMockBuffer("A", range(8 * 14 * 11), shape=(8, 14, 11)))
>>> test_direct_slicing(IntMockBuffer("A", range(8 * 14 * 11), shape=(8, 14, 11)))
# , writable=False))
acquired A
3 9 2
308 -11 1
...
...
@@ -1561,7 +1565,7 @@ def test_direct_slicing(arg):
released A
Test direct slicing, negative slice oob in dim 2
>>> test_direct_slicing(IntMockBuffer("A", range(1 * 2 * 3), shape=(1, 2, 3)))
>>> test_direct_slicing(IntMockBuffer("A", range(1 * 2 * 3), shape=(1, 2, 3)))
# , writable=False))
acquired A
0 0 2
12 -3 1
...
...
@@ -1586,7 +1590,7 @@ def test_direct_slicing(arg):
@
testcase
def
test_slicing_and_indexing
(
arg
):
"""
>>> a = IntStridedMockBuffer("A", range(10 * 3 * 5), shape=(10, 3, 5))
>>> a = IntStridedMockBuffer("A", range(10 * 3 * 5), shape=(10, 3, 5))
# , writable=False)
>>> test_slicing_and_indexing(a)
acquired A
5 2
...
...
@@ -1622,7 +1626,7 @@ def test_oob():
...
IndexError: Index out of bounds (axis 1)
"""
cdef
int
[:,
:]
a
=
IntMockBuffer
(
"A"
,
range
(
4
*
9
),
shape
=
(
4
,
9
))
cdef
int
[:,
:]
a
=
IntMockBuffer
(
"A"
,
range
(
4
*
9
),
shape
=
(
4
,
9
))
# , writable=False)
print
a
[:,
20
]
...
...
@@ -1665,7 +1669,7 @@ def test_nogil_oob2():
...
IndexError: Index out of bounds (axis 0)
"""
cdef
int
[:,
:]
a
=
IntMockBuffer
(
"A"
,
range
(
4
*
9
),
shape
=
(
4
,
9
))
cdef
int
[:,
:]
a
=
IntMockBuffer
(
"A"
,
range
(
4
*
9
),
shape
=
(
4
,
9
))
# , writable=False)
with
nogil
:
a
[
100
,
9
:]
...
...
@@ -1711,7 +1715,7 @@ def test_convert_slicenode_to_indexnode():
2
released A
"""
cdef
int
[:]
a
=
IntMockBuffer
(
"A"
,
range
(
10
),
shape
=
(
10
,))
cdef
int
[:]
a
=
IntMockBuffer
(
"A"
,
range
(
10
),
shape
=
(
10
,))
# , writable=False)
with
nogil
:
a
=
a
[
2
:
4
]
print
a
[
0
]
...
...
@@ -1721,10 +1725,10 @@ def test_convert_slicenode_to_indexnode():
@
cython
.
wraparound
(
False
)
def
test_memslice_prange
(
arg
):
"""
>>> test_memslice_prange(IntMockBuffer("A", range(400), shape=(20, 4, 5)))
>>> test_memslice_prange(IntMockBuffer("A", range(400), shape=(20, 4, 5)))
# FIXME: , writable=False))
acquired A
released A
>>> test_memslice_prange(IntMockBuffer("A", range(200), shape=(100, 2, 1)))
>>> test_memslice_prange(IntMockBuffer("A", range(200), shape=(100, 2, 1)))
# FIXME: , writable=False))
acquired A
released A
"""
...
...
@@ -2388,7 +2392,7 @@ def test_inplace_assignment():
@
testcase
def
test_newaxis
(
int
[:]
one_D
):
"""
>>> A = IntMockBuffer("A", range(6))
>>> A = IntMockBuffer("A", range(6))
# , writable=False)
>>> test_newaxis(A)
acquired A
3
...
...
@@ -2410,7 +2414,7 @@ def test_newaxis(int[:] one_D):
@
testcase
def
test_newaxis2
(
int
[:,
:]
two_D
):
"""
>>> A = IntMockBuffer("A", range(6), shape=(3, 2))
>>> A = IntMockBuffer("A", range(6), shape=(3, 2))
# , writable=False)
>>> test_newaxis2(A)
acquired A
shape: 3 1 1
...
...
@@ -2444,3 +2448,16 @@ def test_newaxis2(int[:, :] two_D):
_print_attributes
(
d
)
@
testcase
def
test_const_buffer
(
const
int
[:]
a
):
"""
>>> A = IntMockBuffer("A", range(6), shape=(6,), writable=False)
>>> test_const_buffer(A)
acquired A
0
5
released A
"""
cdef
const
int
[:]
c
=
a
print
(
a
[
0
])
print
(
c
[
-
1
])
tests/memoryview/numpy_memoryview_readonly.pyx
0 → 100644
View file @
9ca6532b
# mode: run
# tag: readonly, const, numpy
import
numpy
as
np
def
new_array
():
return
np
.
arange
(
10
).
astype
(
'float'
)
ARRAY
=
new_array
()
cdef
getmax
(
const
double
[:]
x
):
"""Example code, should work with both ro and rw memoryviews"""
cdef
double
max_val
=
-
float
(
'inf'
)
for
val
in
x
:
if
val
>
max_val
:
max_val
=
val
return
max_val
cdef
update_array
(
double
[:]
x
):
"""Modifying a ro memoryview should raise an error"""
x
[
0
]
=
23.
cdef
getconst
(
const
double
[:]
x
):
"""Should accept ro memoryviews"""
return
x
[
0
]
def
test_mmview_rw
(
x
):
"""
>>> test_mmview_rw(ARRAY)
9.0
"""
return
getmax
(
x
)
def
test_mmview_ro
(
x
):
"""
>>> test_mmview_ro(new_array())
9.0
"""
x
.
setflags
(
write
=
False
)
assert
x
.
flags
.
writeable
is
False
return
getmax
(
x
)
def
test_update_mmview_rw
(
x
):
"""
>>> test_update_mmview_rw(new_array())
23.0
"""
update_array
(
x
)
return
x
[
0
]
def
test_update_mmview_ro
(
x
):
"""
>>> test_update_mmview_ro(new_array())
0.0
"""
x
.
setflags
(
write
=
False
)
assert
x
.
flags
.
writeable
is
False
try
:
update_array
(
x
)
except
ValueError
:
pass
else
:
assert
False
,
"RO error not raised!"
return
getconst
(
x
)
def
test_rw_call_getmax
(
double
[:]
x
):
"""
>>> test_rw_call_getmax(new_array())
23.0
"""
update_array
(
x
)
assert
getconst
(
x
)
==
23
return
getmax
(
x
)
def
test_const_mmview_ro
(
x
):
"""
>>> test_const_mmview_ro(new_array())
0.0
"""
x
.
setflags
(
write
=
False
)
assert
x
.
flags
.
writeable
is
False
return
getconst
(
x
)
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