[pypy-commit] pypy py3k: hg merge default
rlamy
pypy.commits at gmail.com
Wed Sep 7 00:16:01 EDT 2016
Author: Ronan Lamy <ronan.lamy at gmail.com>
Branch: py3k
Changeset: r86916:37c0e5dcf737
Date: 2016-09-07 05:15 +0100
http://bitbucket.org/pypy/pypy/changeset/37c0e5dcf737/
Log: hg merge default
diff --git a/.hgtags b/.hgtags
--- a/.hgtags
+++ b/.hgtags
@@ -30,3 +30,6 @@
68bb3510d8212ae9efb687e12e58c09d29e74f87 release-pypy2.7-v5.4.0
68bb3510d8212ae9efb687e12e58c09d29e74f87 release-pypy2.7-v5.4.0
77392ad263504df011ccfcabf6a62e21d04086d0 release-pypy2.7-v5.4.0
+050d84dd78997f021acf0e133934275d63547cc0 release-pypy2.7-v5.4.1
+050d84dd78997f021acf0e133934275d63547cc0 release-pypy2.7-v5.4.1
+0e2d9a73f5a1818d0245d75daccdbe21b2d5c3ef release-pypy2.7-v5.4.1
diff --git a/lib_pypy/cffi.egg-info/PKG-INFO b/lib_pypy/cffi.egg-info/PKG-INFO
--- a/lib_pypy/cffi.egg-info/PKG-INFO
+++ b/lib_pypy/cffi.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: cffi
-Version: 1.8.1
+Version: 1.8.2
Summary: Foreign Function Interface for Python calling C code.
Home-page: http://cffi.readthedocs.org
Author: Armin Rigo, Maciej Fijalkowski
diff --git a/lib_pypy/cffi/__init__.py b/lib_pypy/cffi/__init__.py
--- a/lib_pypy/cffi/__init__.py
+++ b/lib_pypy/cffi/__init__.py
@@ -4,8 +4,8 @@
from .api import FFI, CDefError, FFIError
from .ffiplatform import VerificationError, VerificationMissing
-__version__ = "1.8.1"
-__version_info__ = (1, 8, 1)
+__version__ = "1.8.2"
+__version_info__ = (1, 8, 2)
# The verifier module file names are based on the CRC32 of a string that
# contains the following version number. It may be older than __version__
diff --git a/lib_pypy/cffi/_embedding.h b/lib_pypy/cffi/_embedding.h
--- a/lib_pypy/cffi/_embedding.h
+++ b/lib_pypy/cffi/_embedding.h
@@ -233,7 +233,7 @@
f = PySys_GetObject((char *)"stderr");
if (f != NULL && f != Py_None) {
PyFile_WriteString("\nFrom: " _CFFI_MODULE_NAME
- "\ncompiled with cffi version: 1.8.1"
+ "\ncompiled with cffi version: 1.8.2"
"\n_cffi_backend module: ", f);
modules = PyImport_GetModuleDict();
mod = PyDict_GetItemString(modules, "_cffi_backend");
diff --git a/lib_pypy/cffi/backend_ctypes.py b/lib_pypy/cffi/backend_ctypes.py
--- a/lib_pypy/cffi/backend_ctypes.py
+++ b/lib_pypy/cffi/backend_ctypes.py
@@ -1009,6 +1009,12 @@
myref is not None and myref is other())
def __ne__(self, other):
return not (self == other)
+ def __hash__(self):
+ try:
+ return self._hash
+ except AttributeError:
+ self._hash = hash(self())
+ return self._hash
self._weakref_cache_ref = {}, MyRef
weak_cache, MyRef = self._weakref_cache_ref
diff --git a/pypy/doc/index-of-release-notes.rst b/pypy/doc/index-of-release-notes.rst
--- a/pypy/doc/index-of-release-notes.rst
+++ b/pypy/doc/index-of-release-notes.rst
@@ -6,6 +6,7 @@
.. toctree::
+ release-pypy2.7-v5.4.1.rst
release-pypy2.7-v5.4.0.rst
release-pypy2.7-v5.3.1.rst
release-pypy2.7-v5.3.0.rst
diff --git a/pypy/doc/release-pypy2.7-v5.4.1.rst b/pypy/doc/release-pypy2.7-v5.4.1.rst
new file mode 100644
--- /dev/null
+++ b/pypy/doc/release-pypy2.7-v5.4.1.rst
@@ -0,0 +1,64 @@
+==========
+PyPy 5.4.1
+==========
+
+We have released a bugfix for PyPy2.7-v5.4.0, released last week,
+due to the following issues:
+
+ * Update list of contributors in documentation and LICENSE file,
+ this was unfortunately left out of 5.4.0. My apologies to the new
+ contributors
+
+ * Allow tests run with `-A` to find `libm.so` even if it is a script not a
+ dynamically loadable file
+
+ * Bump `sys.setrecursionlimit()` when translating PyPy, for translating with CPython
+
+ * Tweak a float comparison with 0 in `backendopt.inline` to avoid rounding errors
+
+ * Fix for an issue where os.access() accepted a float for mode
+
+ * Fix for and issue where `unicode.decode('utf8', 'custom_replace')` messed up
+ the last byte of a unicode string sometimes
+
+ * Update built-in cffi_ to version 1.8.1
+
+ * Explicitly detect that we found as-yet-unsupported OpenSSL 1.1, and crash
+ translation with a message asking for help porting it
+
+ * Fix a regression where a PyBytesObject was forced (converted to a RPython
+ object) when not required, reported as issue #2395
+
+Thanks to those who reported the issues.
+
+What is PyPy?
+=============
+
+PyPy is a very compliant Python interpreter, almost a drop-in replacement for
+CPython 2.7. It's fast (`PyPy and CPython 2.7.x`_ performance comparison)
+due to its integrated tracing JIT compiler.
+
+We also welcome developers of other
+`dynamic languages`_ to see what RPython can do for them.
+
+This release supports:
+
+ * **x86** machines on most common operating systems
+ (Linux 32/64, Mac OS X 64, Windows 32, OpenBSD, FreeBSD),
+
+ * newer **ARM** hardware (ARMv6 or ARMv7, with VFPv3) running Linux,
+
+ * big- and little-endian variants of **PPC64** running Linux,
+
+ * **s390x** running Linux
+
+.. _cffi: https://cffi.readthedocs.io
+.. _`PyPy and CPython 2.7.x`: http://speed.pypy.org
+.. _`dynamic languages`: http://pypyjs.org
+
+Please update, and continue to help us make PyPy better.
+
+Cheers
+
+The PyPy Team
+
diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -7,3 +7,9 @@
.. branch: rpython-resync
Backport rpython changes made directly on the py3k and py3.5 branches.
+
+.. branch: buffer-interface
+Implement PyObject_GetBuffer, PyMemoryView_GET_BUFFER, and handles memoryviews
+in numpypy
+
+
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -1432,6 +1432,9 @@
BUF_FORMAT = 0x0004
BUF_ND = 0x0008
BUF_STRIDES = 0x0010 | BUF_ND
+ BUF_C_CONTIGUOUS = 0x0020 | BUF_STRIDES
+ BUF_F_CONTIGUOUS = 0x0040 | BUF_STRIDES
+ BUF_ANY_CONTIGUOUS = 0x0080 | BUF_STRIDES
BUF_INDIRECT = 0x0100 | BUF_STRIDES
BUF_CONTIG_RO = BUF_ND
diff --git a/pypy/module/_cffi_backend/__init__.py b/pypy/module/_cffi_backend/__init__.py
--- a/pypy/module/_cffi_backend/__init__.py
+++ b/pypy/module/_cffi_backend/__init__.py
@@ -3,7 +3,7 @@
from rpython.rlib import rdynload, clibffi, entrypoint
from rpython.rtyper.lltypesystem import rffi
-VERSION = "1.8.1"
+VERSION = "1.8.2"
FFI_DEFAULT_ABI = clibffi.FFI_DEFAULT_ABI
try:
diff --git a/pypy/module/_cffi_backend/ctypestruct.py b/pypy/module/_cffi_backend/ctypestruct.py
--- a/pypy/module/_cffi_backend/ctypestruct.py
+++ b/pypy/module/_cffi_backend/ctypestruct.py
@@ -105,9 +105,6 @@
return True
return False
- def _check_only_one_argument_for_union(self, w_ob):
- pass
-
def convert_from_object(self, cdata, w_ob):
if not self._copy_from_same(cdata, w_ob):
self.convert_struct_from_object(cdata, w_ob, optvarsize=-1)
@@ -117,19 +114,24 @@
)
def convert_struct_from_object(self, cdata, w_ob, optvarsize):
self.force_lazy_struct()
- self._check_only_one_argument_for_union(w_ob)
space = self.space
if (space.isinstance_w(w_ob, space.w_list) or
space.isinstance_w(w_ob, space.w_tuple)):
lst_w = space.listview(w_ob)
- if len(lst_w) > len(self._fields_list):
- raise oefmt(space.w_ValueError,
- "too many initializers for '%s' (got %d)",
- self.name, len(lst_w))
- for i in range(len(lst_w)):
- optvarsize = self._fields_list[i].write_v(cdata, lst_w[i],
+ j = 0
+ for w_obj in lst_w:
+ try:
+ while (self._fields_list[j].flags &
+ W_CField.BF_IGNORE_IN_CTOR):
+ j += 1
+ except IndexError:
+ raise oefmt(space.w_ValueError,
+ "too many initializers for '%s' (got %d)",
+ self.name, len(lst_w))
+ optvarsize = self._fields_list[j].write_v(cdata, w_obj,
optvarsize)
+ j += 1
return optvarsize
elif space.isinstance_w(w_ob, space.w_dict):
@@ -185,14 +187,6 @@
class W_CTypeUnion(W_CTypeStructOrUnion):
kind = "union"
- def _check_only_one_argument_for_union(self, w_ob):
- space = self.space
- n = space.int_w(space.len(w_ob))
- if n > 1:
- raise oefmt(space.w_ValueError,
- "initializer for '%s': %d items given, but only one "
- "supported (use a dict if needed)", self.name, n)
-
class W_CField(W_Root):
_immutable_ = True
@@ -200,18 +194,21 @@
BS_REGULAR = -1
BS_EMPTY_ARRAY = -2
- def __init__(self, ctype, offset, bitshift, bitsize):
+ BF_IGNORE_IN_CTOR = 0x01
+
+ def __init__(self, ctype, offset, bitshift, bitsize, flags):
self.ctype = ctype
self.offset = offset
self.bitshift = bitshift # >= 0: bitshift; or BS_REGULAR/BS_EMPTY_ARRAY
self.bitsize = bitsize
+ self.flags = flags # BF_xxx
def is_bitfield(self):
return self.bitshift >= 0
- def make_shifted(self, offset):
+ def make_shifted(self, offset, fflags):
return W_CField(self.ctype, offset + self.offset,
- self.bitshift, self.bitsize)
+ self.bitshift, self.bitsize, self.flags | fflags)
def read(self, cdata):
cdata = rffi.ptradd(cdata, self.offset)
@@ -341,5 +338,6 @@
offset = interp_attrproperty('offset', W_CField),
bitshift = interp_attrproperty('bitshift', W_CField),
bitsize = interp_attrproperty('bitsize', W_CField),
+ flags = interp_attrproperty('flags', W_CField),
)
W_CField.typedef.acceptable_as_base_class = False
diff --git a/pypy/module/_cffi_backend/newtype.py b/pypy/module/_cffi_backend/newtype.py
--- a/pypy/module/_cffi_backend/newtype.py
+++ b/pypy/module/_cffi_backend/newtype.py
@@ -345,6 +345,11 @@
if alignment < falign and do_align:
alignment = falign
#
+ if is_union and i > 0:
+ fflags = ctypestruct.W_CField.BF_IGNORE_IN_CTOR
+ else:
+ fflags = 0
+ #
if fbitsize < 0:
# not a bitfield: common case
@@ -372,7 +377,7 @@
for name, srcfld in ftype._fields_dict.items():
srcfield2names[srcfld] = name
for srcfld in ftype._fields_list:
- fld = srcfld.make_shifted(boffset // 8)
+ fld = srcfld.make_shifted(boffset // 8, fflags)
fields_list.append(fld)
try:
fields_dict[srcfield2names[srcfld]] = fld
@@ -382,7 +387,8 @@
w_ctype._custom_field_pos = True
else:
# a regular field
- fld = ctypestruct.W_CField(ftype, boffset // 8, bs_flag, -1)
+ fld = ctypestruct.W_CField(ftype, boffset // 8, bs_flag, -1,
+ fflags)
fields_list.append(fld)
fields_dict[fname] = fld
@@ -489,7 +495,7 @@
bitshift = 8 * ftype.size - fbitsize- bitshift
fld = ctypestruct.W_CField(ftype, field_offset_bytes,
- bitshift, fbitsize)
+ bitshift, fbitsize, fflags)
fields_list.append(fld)
fields_dict[fname] = fld
diff --git a/pypy/module/_cffi_backend/test/_backend_test_c.py b/pypy/module/_cffi_backend/test/_backend_test_c.py
--- a/pypy/module/_cffi_backend/test/_backend_test_c.py
+++ b/pypy/module/_cffi_backend/test/_backend_test_c.py
@@ -1,7 +1,7 @@
# ____________________________________________________________
import sys
-assert __version__ == "1.8.1", ("This test_c.py file is for testing a version"
+assert __version__ == "1.8.2", ("This test_c.py file is for testing a version"
" of cffi that differs from the one that we"
" get from 'import _cffi_backend'")
if sys.version_info < (3,):
@@ -2525,6 +2525,25 @@
assert d[2][1].bitshift == -1
assert d[2][1].bitsize == -1
+def test_nested_anonymous_struct_2():
+ BInt = new_primitive_type("int")
+ BStruct = new_struct_type("struct foo")
+ BInnerUnion = new_union_type("union bar")
+ complete_struct_or_union(BInnerUnion, [('a1', BInt, -1),
+ ('a2', BInt, -1)])
+ complete_struct_or_union(BStruct, [('b1', BInt, -1),
+ ('', BInnerUnion, -1),
+ ('b2', BInt, -1)])
+ assert sizeof(BInnerUnion) == sizeof(BInt)
+ assert sizeof(BStruct) == sizeof(BInt) * 3
+ fields = [(name, fld.offset, fld.flags) for (name, fld) in BStruct.fields]
+ assert fields == [
+ ('b1', 0 * sizeof(BInt), 0),
+ ('a1', 1 * sizeof(BInt), 0),
+ ('a2', 1 * sizeof(BInt), 1),
+ ('b2', 2 * sizeof(BInt), 0),
+ ]
+
def test_sizeof_union():
# a union has the largest alignment of its members, and a total size
# that is the largest of its items *possibly further aligned* if
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -121,7 +121,7 @@
METH_COEXIST METH_STATIC METH_CLASS Py_TPFLAGS_BASETYPE
METH_NOARGS METH_VARARGS METH_KEYWORDS METH_O Py_TPFLAGS_HAVE_INPLACEOPS
Py_TPFLAGS_HEAPTYPE Py_TPFLAGS_HAVE_CLASS Py_TPFLAGS_HAVE_NEWBUFFER
-Py_LT Py_LE Py_EQ Py_NE Py_GT Py_GE Py_TPFLAGS_CHECKTYPES
+Py_LT Py_LE Py_EQ Py_NE Py_GT Py_GE Py_TPFLAGS_CHECKTYPES Py_MAX_NDIMS
Py_CLEANUP_SUPPORTED
""".split()
for name in constant_names:
@@ -647,6 +647,9 @@
('format', rffi.CCHARP),
('shape', Py_ssize_tP),
('strides', Py_ssize_tP),
+ ('_format', rffi.UCHAR),
+ ('_shape', rffi.CFixedArray(Py_ssize_t, Py_MAX_NDIMS)),
+ ('_strides', rffi.CFixedArray(Py_ssize_t, Py_MAX_NDIMS)),
('suboffsets', Py_ssize_tP),
#('smalltable', rffi.CFixedArray(Py_ssize_t, 2)),
('internal', rffi.VOIDP)
diff --git a/pypy/module/cpyext/buffer.py b/pypy/module/cpyext/buffer.py
--- a/pypy/module/cpyext/buffer.py
+++ b/pypy/module/cpyext/buffer.py
@@ -1,20 +1,66 @@
from pypy.interpreter.error import oefmt
from rpython.rtyper.lltypesystem import rffi, lltype
from rpython.rlib import buffer
+from rpython.rlib.rarithmetic import widen
from pypy.module.cpyext.api import (
cpython_api, CANNOT_FAIL, Py_buffer)
from pypy.module.cpyext.pyobject import PyObject, Py_DecRef
-# PyObject_GetBuffer has been removed, it is defined in abstract.c
-# PyObject_CheckBuffer is also already defined
+def _IsFortranContiguous(view):
+ ndim = widen(view.c_ndim)
+ if ndim == 0:
+ return 1
+ if not view.c_strides:
+ return ndim == 1
+ sd = view.c_itemsize
+ if ndim == 1:
+ return view.c_shape[0] == 1 or sd == view.c_strides[0]
+ for i in range(view.c_ndim):
+ dim = view.c_shape[i]
+ if dim == 0:
+ return 1
+ if view.c_strides[i] != sd:
+ return 0
+ sd *= dim
+ return 1
+
+def _IsCContiguous(view):
+ ndim = widen(view.c_ndim)
+ if ndim == 0:
+ return 1
+ if not view.c_strides:
+ return ndim == 1
+ sd = view.c_itemsize
+ if ndim == 1:
+ return view.c_shape[0] == 1 or sd == view.c_strides[0]
+ for i in range(ndim - 1, -1, -1):
+ dim = view.c_shape[i]
+ if dim == 0:
+ return 1
+ if view.c_strides[i] != sd:
+ return 0
+ sd *= dim
+ return 1
+
@cpython_api([lltype.Ptr(Py_buffer), lltype.Char], rffi.INT_real, error=CANNOT_FAIL)
-def PyBuffer_IsContiguous(space, view, fortran):
+def PyBuffer_IsContiguous(space, view, fort):
"""Return 1 if the memory defined by the view is C-style (fortran is
'C') or Fortran-style (fortran is 'F') contiguous or either one
(fortran is 'A'). Return 0 otherwise."""
- # PyPy only supports contiguous Py_buffers for now.
- return 1
+ # traverse the strides, checking for consistent stride increases from
+ # right-to-left (c) or left-to-right (fortran). Copied from cpython
+ if not view.c_suboffsets:
+ return 0
+ if (fort == 'C'):
+ return _IsCContiguous(view)
+ elif (fort == 'F'):
+ return _IsFortranContiguous(view)
+ elif (fort == 'A'):
+ return (_IsCContiguous(view) or _IsFortranContiguous(view))
+ return 0
+
+
class CBuffer(buffer.Buffer):
diff --git a/pypy/module/cpyext/bytesobject.py b/pypy/module/cpyext/bytesobject.py
--- a/pypy/module/cpyext/bytesobject.py
+++ b/pypy/module/cpyext/bytesobject.py
@@ -14,45 +14,33 @@
## Implementation of PyBytesObject
## ================================
##
-## The problem
-## -----------
+## PyBytesObject has its own ob_sval buffer, so we have two copies of a string;
+## one in the PyBytesObject returned from various C-API functions and another
+## in the corresponding RPython object.
##
-## PyBytes_AsString() must return a (non-movable) pointer to the underlying
-## ob_sval, whereas pypy strings are movable. C code may temporarily store
-## this address and use it, as long as it owns a reference to the PyObject.
-## There is no "release" function to specify that the pointer is not needed
-## any more.
+## The following calls can create a PyBytesObject without a correspoinding
+## RPython object:
##
-## Also, the pointer may be used to fill the initial value of string. This is
-## valid only when the string was just allocated, and is not used elsewhere.
+## PyBytes_FromStringAndSize(NULL, n) / PyString_FromStringAndSize(NULL, n)
##
-## Solution
-## --------
+## In the PyBytesObject returned, the ob_sval buffer may be modified as
+## long as the freshly allocated PyBytesObject is not "forced" via a call
+## to any of the more sophisticated C-API functions.
##
-## PyBytesObject contains two additional members: the ob_size and a pointer to a
-## char ob_sval; it may be NULL.
-##
-## - A string allocated by pypy will be converted into a PyBytesObject with a
-## NULL buffer. The first time PyBytes_AsString() is called, memory is
-## allocated (with flavor='raw') and content is copied.
-##
-## - A string allocated with PyBytes_FromStringAndSize(NULL, size) will
-## allocate a PyBytesObject structure, and a buffer with the specified
-## size+1, but the reference won't be stored in the global map; there is no
-## corresponding object in pypy. When from_ref() or Py_INCREF() is called,
-## the pypy string is created, and added to the global map of tracked
-## objects. The buffer is then supposed to be immutable.
-##
-##- A buffer obtained from PyBytes_AS_STRING() could be mutable iff
-## there is no corresponding pypy object for the string
-##
-## - _PyBytes_Resize() works only on not-yet-pypy'd strings, and returns a
-## similar object.
-##
-## - PyBytes_Size() doesn't need to force the object.
+## Care has been taken in implementing the functions below, so that
+## if they are called with a non-forced PyBytesObject, they will not
+## unintentionally force the creation of a RPython object. As long as only these
+## are used, the ob_sval buffer is still modifiable:
+##
+## PyBytes_AsString / PyString_AsString
+## PyBytes_AS_STRING / PyString_AS_STRING
+## PyBytes_AsStringAndSize / PyString_AsStringAndSize
+## PyBytes_Size / PyString_Size
+## PyBytes_Resize / PyString_Resize
+## _PyBytes_Resize / _PyString_Resize (raises if called with a forced object)
##
## - There could be an (expensive!) check in from_ref() that the buffer still
-## corresponds to the pypy gc-managed string.
+## corresponds to the pypy gc-managed string,
##
PyBytesObjectStruct = lltype.ForwardReference()
@@ -150,9 +138,6 @@
raise oefmt(space.w_TypeError,
"expected bytes, %T found", from_ref(space, ref))
ref_str = rffi.cast(PyBytesObject, ref)
- if not pyobj_has_w_obj(ref):
- # XXX Force the ref?
- bytes_realize(space, ref)
return ref_str.c_ob_sval
@cpython_api([rffi.VOIDP], rffi.CCHARP, error=0)
@@ -170,9 +155,6 @@
if not PyBytes_Check(space, ref):
raise oefmt(space.w_TypeError,
"expected bytes, %T found", from_ref(space, ref))
- if not pyobj_has_w_obj(ref):
- # force the ref
- bytes_realize(space, ref)
ref_str = rffi.cast(PyBytesObject, ref)
data[0] = ref_str.c_ob_sval
if length:
diff --git a/pypy/module/cpyext/include/object.h b/pypy/module/cpyext/include/object.h
--- a/pypy/module/cpyext/include/object.h
+++ b/pypy/module/cpyext/include/object.h
@@ -131,7 +131,8 @@
typedef int(*objobjargproc)(PyObject *, PyObject *, PyObject *);
-/* Py3k buffer interface */
+/* Py3k buffer interface, adapted for PyPy */
+#define Py_MAX_NDIMS 32
typedef struct bufferinfo {
void *buf;
PyObject *obj; /* owned reference */
@@ -145,12 +146,14 @@
char *format;
Py_ssize_t *shape;
Py_ssize_t *strides;
- Py_ssize_t *suboffsets;
-
+ Py_ssize_t *suboffsets; /* alway NULL for app-level objects*/
+ unsigned char _format;
+ Py_ssize_t _strides[Py_MAX_NDIMS];
+ Py_ssize_t _shape[Py_MAX_NDIMS];
/* static store for shape and strides of
mono-dimensional buffers. */
/* Py_ssize_t smalltable[2]; */
- void *internal;
+ void *internal; /* always NULL for app-level objects */
} Py_buffer;
diff --git a/pypy/module/cpyext/include/patchlevel.h b/pypy/module/cpyext/include/patchlevel.h
--- a/pypy/module/cpyext/include/patchlevel.h
+++ b/pypy/module/cpyext/include/patchlevel.h
@@ -29,8 +29,8 @@
#define PY_VERSION "3.3.5"
/* PyPy version as a string */
-#define PYPY_VERSION "5.4.1-alpha0"
-#define PYPY_VERSION_NUM 0x05040100
+#define PYPY_VERSION "5.5.0-alpha0"
+#define PYPY_VERSION_NUM 0x05050000
/* Defined to mean a PyPy where cpyext holds more regular references
to PyObjects, e.g. staying alive as long as the internal PyPy object
diff --git a/pypy/module/cpyext/memoryobject.py b/pypy/module/cpyext/memoryobject.py
--- a/pypy/module/cpyext/memoryobject.py
+++ b/pypy/module/cpyext/memoryobject.py
@@ -1,7 +1,8 @@
from pypy.module.cpyext.api import (cpython_api, Py_buffer, CANNOT_FAIL,
- build_type_checkers)
-from pypy.module.cpyext.pyobject import PyObject
-from rpython.rtyper.lltypesystem import lltype
+ Py_MAX_NDIMS, build_type_checkers, Py_ssize_tP)
+from pypy.module.cpyext.pyobject import PyObject, make_ref, incref
+from rpython.rtyper.lltypesystem import lltype, rffi
+from pypy.objspace.std.memoryobject import W_MemoryView
from pypy.interpreter.error import oefmt
from pypy.module.cpyext.pyobject import PyObject, from_ref
@@ -16,6 +17,7 @@
@cpython_api([PyObject], PyObject)
def PyMemoryView_GET_BASE(space, w_obj):
# return the obj field of the Py_buffer created by PyMemoryView_GET_BUFFER
+ # XXX needed for numpy on py3k
raise NotImplementedError('PyMemoryView_GET_BUFFER')
@cpython_api([PyObject], lltype.Ptr(Py_buffer), error=CANNOT_FAIL)
@@ -24,24 +26,38 @@
object. The object must be a memoryview instance; this macro doesn't
check its type, you must do it yourself or you will risk crashes."""
view = lltype.malloc(Py_buffer, flavor='raw', zero=True)
- # TODO - fill in fields
- '''
- view.c_buf = buf
- view.c_len = length
- view.c_obj = obj
- Py_IncRef(space, obj)
- view.c_itemsize = 1
- rffi.setintfield(view, 'c_readonly', readonly)
- rffi.setintfield(view, 'c_ndim', 0)
- view.c_format = lltype.nullptr(rffi.CCHARP.TO)
- view.c_shape = lltype.nullptr(Py_ssize_tP.TO)
- view.c_strides = lltype.nullptr(Py_ssize_tP.TO)
+ if not isinstance(w_obj, W_MemoryView):
+ return view
+ ndim = w_obj.buf.getndim()
+ if ndim >= Py_MAX_NDIMS:
+ # XXX warn?
+ return view
+ try:
+ view.c_buf = rffi.cast(rffi.VOIDP, w_obj.buf.get_raw_address())
+ view.c_obj = make_ref(space, w_obj)
+ rffi.setintfield(view, 'c_readonly', w_obj.buf.readonly)
+ isstr = False
+ except ValueError:
+ w_s = w_obj.descr_tobytes(space)
+ view.c_obj = make_ref(space, w_s)
+ rffi.setintfield(view, 'c_readonly', 1)
+ isstr = True
+ view.c_len = w_obj.getlength()
+ view.c_itemsize = w_obj.buf.getitemsize()
+ rffi.setintfield(view, 'c_ndim', ndim)
+ view.c__format = rffi.cast(rffi.UCHAR, w_obj.buf.getformat())
+ view.c_format = rffi.cast(rffi.CCHARP, view.c__format)
+ view.c_shape = rffi.cast(Py_ssize_tP, view.c__shape)
+ view.c_strides = rffi.cast(Py_ssize_tP, view.c__strides)
+ shape = w_obj.buf.getshape()
+ strides = w_obj.buf.getstrides()
+ for i in range(ndim):
+ view.c_shape[i] = shape[i]
+ view.c_strides[i] = strides[i]
view.c_suboffsets = lltype.nullptr(Py_ssize_tP.TO)
view.c_internal = lltype.nullptr(rffi.VOIDP.TO)
- '''
return view
-
@cpython_api([lltype.Ptr(Py_buffer)], PyObject)
def PyMemoryView_FromBuffer(space, view):
"""Create a memoryview object wrapping the given buffer structure view.
diff --git a/pypy/module/cpyext/slotdefs.py b/pypy/module/cpyext/slotdefs.py
--- a/pypy/module/cpyext/slotdefs.py
+++ b/pypy/module/cpyext/slotdefs.py
@@ -335,9 +335,15 @@
def getshape(self):
return self.shape
+ def getstrides(self):
+ return self.strides
+
def getitemsize(self):
return self.itemsize
+ def getndim(self):
+ return self.ndim
+
def wrap_getbuffer(space, w_self, w_args, func):
func_target = rffi.cast(getbufferproc, func)
with lltype.scoped_alloc(Py_buffer) as pybuf:
diff --git a/pypy/module/cpyext/test/buffer_test.c b/pypy/module/cpyext/test/buffer_test.c
--- a/pypy/module/cpyext/test/buffer_test.c
+++ b/pypy/module/cpyext/test/buffer_test.c
@@ -107,14 +107,11 @@
PyMyArray_getbuffer(PyObject *obj, Py_buffer *view, int flags)
{
PyMyArray* self = (PyMyArray*)obj;
- fprintf(stdout, "in PyMyArray_getbuffer\n");
if (view == NULL) {
- fprintf(stdout, "view is NULL\n");
PyErr_SetString(PyExc_ValueError, "NULL view in getbuffer");
return -1;
}
if (flags == 0) {
- fprintf(stdout, "flags is 0\n");
PyErr_SetString(PyExc_ValueError, "flags == 0 in getbuffer");
return -1;
}
@@ -188,7 +185,131 @@
(initproc)PyMyArray_init, /* tp_init */
};
+static PyObject*
+test_buffer(PyObject* self, PyObject* args)
+{
+ Py_buffer* view = NULL;
+ PyObject* obj = PyTuple_GetItem(args, 0);
+ PyObject* memoryview = PyMemoryView_FromObject(obj);
+ if (memoryview == NULL)
+ return PyInt_FromLong(-1);
+ view = PyMemoryView_GET_BUFFER(memoryview);
+ Py_DECREF(memoryview);
+ return PyInt_FromLong(view->len);
+}
+
+/* Copied from numpy tests */
+/*
+ * Create python string from a FLAG and or the corresponding PyBuf flag
+ * for the use in get_buffer_info.
+ */
+#define GET_PYBUF_FLAG(FLAG) \
+ buf_flag = PyUnicode_FromString(#FLAG); \
+ flag_matches = PyObject_RichCompareBool(buf_flag, tmp, Py_EQ); \
+ Py_DECREF(buf_flag); \
+ if (flag_matches == 1) { \
+ Py_DECREF(tmp); \
+ flags |= PyBUF_##FLAG; \
+ continue; \
+ } \
+ else if (flag_matches == -1) { \
+ Py_DECREF(tmp); \
+ return NULL; \
+ }
+
+
+/*
+ * Get information for a buffer through PyBuf_GetBuffer with the
+ * corresponding flags or'ed. Note that the python caller has to
+ * make sure that or'ing those flags actually makes sense.
+ * More information should probably be returned for future tests.
+ */
+static PyObject *
+get_buffer_info(PyObject *self, PyObject *args)
+{
+ PyObject *buffer_obj, *pyflags;
+ PyObject *tmp, *buf_flag;
+ Py_buffer buffer;
+ PyObject *shape, *strides;
+ Py_ssize_t i, n;
+ int flag_matches;
+ int flags = 0;
+
+ if (!PyArg_ParseTuple(args, "OO", &buffer_obj, &pyflags)) {
+ return NULL;
+ }
+
+ n = PySequence_Length(pyflags);
+ if (n < 0) {
+ return NULL;
+ }
+
+ for (i=0; i < n; i++) {
+ tmp = PySequence_GetItem(pyflags, i);
+ if (tmp == NULL) {
+ return NULL;
+ }
+
+ GET_PYBUF_FLAG(SIMPLE);
+ GET_PYBUF_FLAG(WRITABLE);
+ GET_PYBUF_FLAG(STRIDES);
+ GET_PYBUF_FLAG(ND);
+ GET_PYBUF_FLAG(C_CONTIGUOUS);
+ GET_PYBUF_FLAG(F_CONTIGUOUS);
+ GET_PYBUF_FLAG(ANY_CONTIGUOUS);
+ GET_PYBUF_FLAG(INDIRECT);
+ GET_PYBUF_FLAG(FORMAT);
+ GET_PYBUF_FLAG(STRIDED);
+ GET_PYBUF_FLAG(STRIDED_RO);
+ GET_PYBUF_FLAG(RECORDS);
+ GET_PYBUF_FLAG(RECORDS_RO);
+ GET_PYBUF_FLAG(FULL);
+ GET_PYBUF_FLAG(FULL_RO);
+ GET_PYBUF_FLAG(CONTIG);
+ GET_PYBUF_FLAG(CONTIG_RO);
+
+ Py_DECREF(tmp);
+
+ /* One of the flags must match */
+ PyErr_SetString(PyExc_ValueError, "invalid flag used.");
+ return NULL;
+ }
+
+ if (PyObject_GetBuffer(buffer_obj, &buffer, flags) < 0) {
+ return NULL;
+ }
+
+ if (buffer.shape == NULL) {
+ Py_INCREF(Py_None);
+ shape = Py_None;
+ }
+ else {
+ shape = PyTuple_New(buffer.ndim);
+ for (i=0; i < buffer.ndim; i++) {
+ PyTuple_SET_ITEM(shape, i, PyLong_FromSsize_t(buffer.shape[i]));
+ }
+ }
+
+ if (buffer.strides == NULL) {
+ Py_INCREF(Py_None);
+ strides = Py_None;
+ }
+ else {
+ strides = PyTuple_New(buffer.ndim);
+ for (i=0; i < buffer.ndim; i++) {
+ PyTuple_SET_ITEM(strides, i, PyLong_FromSsize_t(buffer.strides[i]));
+ }
+ }
+
+ PyBuffer_Release(&buffer);
+ return Py_BuildValue("(NN)", shape, strides);
+}
+
+
+
static PyMethodDef buffer_functions[] = {
+ {"test_buffer", (PyCFunction)test_buffer, METH_VARARGS, NULL},
+ {"get_buffer_info", (PyCFunction)get_buffer_info, METH_VARARGS, NULL},
{NULL, NULL} /* Sentinel */
};
diff --git a/pypy/module/cpyext/test/test_bytesobject.py b/pypy/module/cpyext/test/test_bytesobject.py
--- a/pypy/module/cpyext/test/test_bytesobject.py
+++ b/pypy/module/cpyext/test/test_bytesobject.py
@@ -179,8 +179,27 @@
Py_INCREF(Py_None);
return Py_None;
"""),
+ ("c_only", "METH_NOARGS",
+ """
+ int ret;
+ char * buf2;
+ PyObject * obj = PyBytes_FromStringAndSize(NULL, 1024);
+ if (!obj)
+ return NULL;
+ buf2 = PyBytes_AsString(obj);
+ if (!buf2)
+ return NULL;
+ /* buf should not have been forced, issue #2395 */
+ ret = _PyBytes_Resize(&obj, 512);
+ if (ret < 0)
+ return NULL;
+ Py_DECREF(obj);
+ Py_INCREF(Py_None);
+ return Py_None;
+ """),
])
module.getbytes()
+ module.c_only()
class TestBytes(BaseApiTest):
diff --git a/pypy/module/cpyext/test/test_memoryobject.py b/pypy/module/cpyext/test/test_memoryobject.py
--- a/pypy/module/cpyext/test/test_memoryobject.py
+++ b/pypy/module/cpyext/test/test_memoryobject.py
@@ -1,6 +1,6 @@
from pypy.module.cpyext.test.test_api import BaseApiTest
from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
-
+from rpython.rlib.buffer import StringBuffer
class TestMemoryViewObject(BaseApiTest):
def test_fromobject(self, space, api):
w_hello = space.newbytes("hello")
@@ -11,6 +11,13 @@
w_bytes = space.call_method(w_view, "tobytes")
assert space.unwrap(w_bytes) == "hello"
+ def test_frombuffer(self, space, api):
+ w_buf = space.newbuffer(StringBuffer("hello"))
+ w_memoryview = api.PyMemoryView_FromObject(w_buf)
+ w_view = api.PyMemoryView_GET_BUFFER(w_memoryview)
+ ndim = w_view.c_ndim
+ assert ndim == 1
+
class AppTestPyBuffer_FillInfo(AppTestCpythonExtensionBase):
def test_fillWithObject(self):
module = self.import_extension('foo', [
@@ -62,6 +69,25 @@
y = memoryview(arr)
assert y.format == 'i'
assert y.shape == (10,)
+ assert len(y) == 10
s = y[3]
assert len(s) == struct.calcsize('i')
assert s == struct.pack('i', 3)
+ viewlen = module.test_buffer(arr)
+ assert viewlen == y.itemsize * len(y)
+
+ def test_buffer_info(self):
+ from _numpypy import multiarray as np
+ module = self.import_module(name='buffer_test')
+ get_buffer_info = module.get_buffer_info
+ # test_export_flags from numpy test_multiarray
+ raises(ValueError, get_buffer_info, np.arange(5)[::2], ('SIMPLE',))
+ # test_relaxed_strides from numpy test_multiarray
+ arr = np.zeros((1, 10))
+ if arr.flags.f_contiguous:
+ shape, strides = get_buffer_info(arr, ['F_CONTIGUOUS'])
+ assert strides[0] == 8
+ arr = np.ones((10, 1), order='F')
+ shape, strides = get_buffer_info(arr, ['C_CONTIGUOUS'])
+ assert strides[-1] == 8
+
diff --git a/pypy/module/cpyext/test/test_version.py b/pypy/module/cpyext/test/test_version.py
--- a/pypy/module/cpyext/test/test_version.py
+++ b/pypy/module/cpyext/test/test_version.py
@@ -41,9 +41,11 @@
assert module.py_minor_version == sys.version_info.minor
assert module.py_micro_version == sys.version_info.micro
- @pytest.mark.skipif('__pypy__' not in sys.builtin_module_names, reason='pypy only test')
+ #@pytest.mark.skipif('__pypy__' not in sys.builtin_module_names, reason='pypy only test')
def test_pypy_versions(self):
import sys
+ if '__pypy__' not in sys.builtin_module_names:
+ py.test.skip("pypy only test")
init = """
if (Py_IsInitialized()) {
PyObject *m = Py_InitModule("foo", NULL);
diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py
--- a/pypy/module/cpyext/typeobject.py
+++ b/pypy/module/cpyext/typeobject.py
@@ -293,6 +293,8 @@
STRUCT_TYPE = PyNumberMethods
elif slot_names[0] == 'c_tp_as_sequence':
STRUCT_TYPE = PySequenceMethods
+ elif slot_names[0] == 'c_tp_as_buffer':
+ STRUCT_TYPE = PyBufferProcs
else:
raise AssertionError(
"Structure not allocated: %s" % (slot_names[0],))
diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py
--- a/pypy/module/micronumpy/compile.py
+++ b/pypy/module/micronumpy/compile.py
@@ -460,6 +460,9 @@
def getdictvalue(self, space, key):
return self.items[key]
+ def descr_memoryview(self, space, buf):
+ raise oefmt(space.w_TypeError, "error")
+
class IterDictObject(W_Root):
def __init__(self, space, w_dict):
self.space = space
diff --git a/pypy/module/micronumpy/concrete.py b/pypy/module/micronumpy/concrete.py
--- a/pypy/module/micronumpy/concrete.py
+++ b/pypy/module/micronumpy/concrete.py
@@ -377,7 +377,25 @@
def __exit__(self, typ, value, traceback):
keepalive_until_here(self)
- def get_buffer(self, space, readonly):
+ def get_buffer(self, space, flags):
+ errtype = space.w_ValueError # should be BufferError, numpy does this instead
+ if ((flags & space.BUF_C_CONTIGUOUS) == space.BUF_C_CONTIGUOUS and
+ not self.flags & NPY.ARRAY_C_CONTIGUOUS):
+ raise oefmt(errtype, "ndarray is not C-contiguous")
+ if ((flags & space.BUF_F_CONTIGUOUS) == space.BUF_F_CONTIGUOUS and
+ not self.flags & NPY.ARRAY_F_CONTIGUOUS):
+ raise oefmt(errtype, "ndarray is not Fortran contiguous")
+ if ((flags & space.BUF_ANY_CONTIGUOUS) == space.BUF_ANY_CONTIGUOUS and
+ not (self.flags & NPY.ARRAY_F_CONTIGUOUS and
+ self.flags & NPY.ARRAY_C_CONTIGUOUS)):
+ raise oefmt(errtype, "ndarray is not contiguous")
+ if ((flags & space.BUF_STRIDES) != space.BUF_STRIDES and
+ not self.flags & NPY.ARRAY_C_CONTIGUOUS):
+ raise oefmt(errtype, "ndarray is not C-contiguous")
+ if ((flags & space.BUF_WRITABLE) == space.BUF_WRITABLE and
+ not self.flags & NPY.ARRAY_WRITEABLE):
+ raise oefmt(errtype, "buffer source array is read-only")
+ readonly = not (flags & space.BUF_WRITABLE) == space.BUF_WRITABLE
return ArrayBuffer(self, readonly)
def astype(self, space, dtype, order, copy=True):
@@ -695,6 +713,7 @@
index + self.impl.start)
def setitem(self, index, v):
+ # XXX what if self.readonly?
raw_storage_setitem(self.impl.storage, index + self.impl.start,
rffi.cast(lltype.Char, v))
diff --git a/pypy/module/micronumpy/ctors.py b/pypy/module/micronumpy/ctors.py
--- a/pypy/module/micronumpy/ctors.py
+++ b/pypy/module/micronumpy/ctors.py
@@ -1,4 +1,5 @@
from pypy.interpreter.error import OperationError, oefmt
+from pypy.interpreter.baseobjspace import BufferInterfaceNotFound
from pypy.interpreter.gateway import unwrap_spec, WrappedDefault
from rpython.rlib.buffer import SubBuffer
from rpython.rlib.rstring import strip_spaces
@@ -42,7 +43,7 @@
raise oefmt(space.w_ValueError,
"object __array__ method not producing an array")
-def try_interface_method(space, w_object):
+def try_interface_method(space, w_object, copy):
try:
w_interface = space.getattr(w_object, space.wrap("__array_interface__"))
if w_interface is None:
@@ -81,17 +82,20 @@
raise oefmt(space.w_ValueError,
"__array_interface__ could not decode dtype %R", w_dtype
)
- if w_data is not None and (space.isinstance_w(w_data, space.w_tuple) or space.isinstance_w(w_data, space.w_list)):
+ if w_data is not None and (space.isinstance_w(w_data, space.w_tuple) or
+ space.isinstance_w(w_data, space.w_list)):
data_w = space.listview(w_data)
- data = rffi.cast(RAW_STORAGE_PTR, space.int_w(data_w[0]))
- read_only = True # XXX why not space.is_true(data_w[1])
+ w_data = rffi.cast(RAW_STORAGE_PTR, space.int_w(data_w[0]))
+ read_only = space.is_true(data_w[1]) or copy
offset = 0
- return W_NDimArray.from_shape_and_storage(space, shape, data,
- dtype, strides=strides, start=offset), read_only
+ w_base = w_object
+ if read_only:
+ w_base = None
+ return W_NDimArray.from_shape_and_storage(space, shape, w_data,
+ dtype, w_base=w_base, strides=strides,
+ start=offset), read_only
if w_data is None:
- data = w_object
- else:
- data = w_data
+ w_data = w_object
w_offset = space.finditem(w_interface, space.wrap('offset'))
if w_offset is None:
offset = 0
@@ -101,7 +105,7 @@
if strides is not None:
raise oefmt(space.w_NotImplementedError,
"__array_interface__ strides not fully supported yet")
- arr = frombuffer(space, data, dtype, support.product(shape), offset)
+ arr = frombuffer(space, w_data, dtype, support.product(shape), offset)
new_impl = arr.implementation.reshape(arr, shape)
return W_NDimArray(new_impl), False
@@ -110,6 +114,78 @@
return None, False
raise
+def _descriptor_from_pep3118_format(space, c_format):
+ descr = descriptor.decode_w_dtype(space, space.wrap(c_format))
+ if descr:
+ return descr
+ msg = "invalid PEP 3118 format string: '%s'" % c_format
+ space.warn(space.wrap(msg), space.w_RuntimeWarning)
+ return None
+
+def _array_from_buffer_3118(space, w_object, dtype):
+ try:
+ w_buf = space.call_method(space.builtin, "memoryview", w_object)
+ except OperationError as e:
+ if e.match(space, space.w_TypeError):
+ # object does not have buffer interface
+ return w_object
+ raise
+ format = space.getattr(w_buf,space.newbytes('format'))
+ if format:
+ descr = _descriptor_from_pep3118_format(space, space.str_w(format))
+ if not descr:
+ return w_object
+ if dtype and descr:
+ raise oefmt(space.w_NotImplementedError,
+ "creating an array from a memoryview while specifying dtype "
+ "not supported")
+ if descr.elsize != space.int_w(space.getattr(w_buf, space.newbytes('itemsize'))):
+ msg = ("Item size computed from the PEP 3118 buffer format "
+ "string does not match the actual item size.")
+ space.warn(space.wrap(msg), space.w_RuntimeWarning)
+ return w_object
+ dtype = descr
+ elif not dtype:
+ dtype = descriptor.get_dtype_cache(space).w_stringdtype
+ dtype.elsize = space.int_w(space.getattr(w_buf, space.newbytes('itemsize')))
+ nd = space.int_w(space.getattr(w_buf, space.newbytes('ndim')))
+ shape = [space.int_w(d) for d in space.listview(
+ space.getattr(w_buf, space.newbytes('shape')))]
+ strides = []
+ buflen = space.len_w(w_buf) * dtype.elsize
+ if shape:
+ strides = [space.int_w(d) for d in space.listview(
+ space.getattr(w_buf, space.newbytes('strides')))]
+ if not strides:
+ d = buflen
+ strides = [0] * nd
+ for k in range(nd):
+ if shape[k] > 0:
+ d /= shape[k]
+ strides[k] = d
+ else:
+ if nd == 1:
+ shape = [buflen / dtype.elsize, ]
+ strides = [dtype.elsize, ]
+ elif nd > 1:
+ msg = ("ndim computed from the PEP 3118 buffer format "
+ "is greater than 1, but shape is NULL.")
+ space.warn(space.wrap(msg), space.w_RuntimeWarning)
+ return w_object
+ try:
+ w_data = rffi.cast(RAW_STORAGE_PTR, space.int_w(space.call_method(w_buf, '_pypy_raw_address')))
+ except OperationError as e:
+ if e.match(space, space.w_ValueError):
+ return w_object
+ else:
+ raise e
+ writable = not space.bool_w(space.getattr(w_buf, space.newbytes('readonly')))
+ w_ret = W_NDimArray.from_shape_and_storage(space, shape, w_data,
+ storage_bytes=buflen, dtype=dtype, w_base=w_object,
+ writable=writable, strides=strides)
+ if w_ret:
+ return w_ret
+ return w_object
@unwrap_spec(ndmin=int, copy=bool, subok=bool)
def array(space, w_object, w_dtype=None, copy=True, w_order=None, subok=False,
@@ -127,6 +203,7 @@
def _array(space, w_object, w_dtype=None, copy=True, w_order=None, subok=False):
+ from pypy.module.micronumpy.boxes import W_GenericBox
# numpy testing calls array(type(array([]))) and expects a ValueError
if space.isinstance_w(w_object, space.w_type):
raise oefmt(space.w_ValueError, "cannot create ndarray from type instance")
@@ -134,13 +211,19 @@
dtype = descriptor.decode_w_dtype(space, w_dtype)
if not isinstance(w_object, W_NDimArray):
w_array = try_array_method(space, w_object, w_dtype)
- if w_array is not None:
+ if w_array is None:
+ if ( not space.isinstance_w(w_object, space.w_str) and
+ not space.isinstance_w(w_object, space.w_unicode) and
+ not isinstance(w_object, W_GenericBox)):
+ # use buffer interface
+ w_object = _array_from_buffer_3118(space, w_object, dtype)
+ else:
# continue with w_array, but do further operations in place
w_object = w_array
copy = False
dtype = w_object.get_dtype()
if not isinstance(w_object, W_NDimArray):
- w_array, _copy = try_interface_method(space, w_object)
+ w_array, _copy = try_interface_method(space, w_object, copy)
if w_array is not None:
w_object = w_array
copy = _copy
diff --git a/pypy/module/micronumpy/ndarray.py b/pypy/module/micronumpy/ndarray.py
--- a/pypy/module/micronumpy/ndarray.py
+++ b/pypy/module/micronumpy/ndarray.py
@@ -806,10 +806,10 @@
def buffer_w(self, space, flags):
# XXX format isn't always 'B' probably
- return self.implementation.get_buffer(space, True)
+ return self.implementation.get_buffer(space, flags)
def descr_get_data(self, space):
- return space.newbuffer(self.implementation.get_buffer(space, False))
+ return space.newbuffer(self.implementation.get_buffer(space, space.BUF_FULL))
@unwrap_spec(offset=int, axis1=int, axis2=int)
def descr_diagonal(self, space, offset=0, axis1=0, axis2=1):
diff --git a/pypy/module/micronumpy/test/test_ndarray.py b/pypy/module/micronumpy/test/test_ndarray.py
--- a/pypy/module/micronumpy/test/test_ndarray.py
+++ b/pypy/module/micronumpy/test/test_ndarray.py
@@ -3206,7 +3206,9 @@
raises(TypeError, array, Dummy({'version': 3, 'typestr': 'f8', 'shape': ('a', 3)}))
a = array([1, 2, 3])
- b = array(Dummy(a.__array_interface__))
+ d = Dummy(a.__array_interface__)
+ b = array(d)
+ assert b.base is None
b[1] = 200
assert a[1] == 2 # upstream compatibility, is this a bug?
interface_a = a.__array_interface__
@@ -3217,6 +3219,8 @@
interface_b.pop('data')
interface_a.pop('data')
assert interface_a == interface_b
+ b = array(d, copy=False)
+ assert b.base is d
b = array(Dummy({'version':3, 'shape': (50,), 'typestr': 'u1',
'data': 'a'*100}))
@@ -3585,6 +3589,7 @@
cls.w_float32val = cls.space.wrap(struct.pack('f', 5.2))
cls.w_float64val = cls.space.wrap(struct.pack('d', 300.4))
cls.w_ulongval = cls.space.wrap(struct.pack('L', 12))
+ cls.w_one = cls.space.wrap(struct.pack('i', 1))
def test_frombuffer(self):
import numpy as np
@@ -3636,8 +3641,6 @@
else:
EMPTY = None
x = np.array([1, 2, 3, 4, 5], dtype='i')
- y = memoryview('abc')
- assert y.format == 'B'
y = memoryview(x)
assert y.format == 'i'
assert y.shape == (5,)
@@ -3645,6 +3648,16 @@
assert y.strides == (4,)
assert y.suboffsets == EMPTY
assert y.itemsize == 4
+ assert isinstance(y, memoryview)
+ assert y[0] == self.one
+ assert (np.array(y) == x).all()
+
+ x = np.array([0, 0, 0, 0], dtype='O')
+ y = memoryview(x)
+ # handles conversion of address to pinned object?
+ z = np.array(y)
+ assert z.dtype == 'O'
+ assert (z == x).all()
def test_fromstring(self):
import sys
diff --git a/pypy/module/micronumpy/test/test_subtype.py b/pypy/module/micronumpy/test/test_subtype.py
--- a/pypy/module/micronumpy/test/test_subtype.py
+++ b/pypy/module/micronumpy/test/test_subtype.py
@@ -702,3 +702,32 @@
ret = obj.sum()
print type(ret)
assert ret.info == 'spam'
+
+ def test_ndarray_subclass_assigns_base(self):
+ import numpy as np
+ init_called = []
+ class _DummyArray(object):
+ """ Dummy object that just exists to hang __array_interface__ dictionaries
+ and possibly keep alive a reference to a base array.
+ """
+ def __init__(self, interface, base=None):
+ self.__array_interface__ = interface
+ init_called.append(1)
+ self.base = base
+
+ x = np.zeros(10)
+ d = _DummyArray(x.__array_interface__, base=x)
+ y = np.array(d, copy=False)
+ assert sum(init_called) == 1
+ assert y.base is d
+
+ x = np.zeros((0,), dtype='float32')
+ intf = x.__array_interface__.copy()
+ intf["strides"] = x.strides
+ x.__array_interface__["strides"] = x.strides
+ d = _DummyArray(x.__array_interface__, base=x)
+ y = np.array(d, copy=False)
+ assert sum(init_called) == 2
+ assert y.base is d
+
+
diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py
--- a/pypy/module/micronumpy/types.py
+++ b/pypy/module/micronumpy/types.py
@@ -1851,7 +1851,7 @@
arr.gcstruct)
def read(self, arr, i, offset, dtype):
- if arr.gcstruct is V_OBJECTSTORE:
+ if arr.gcstruct is V_OBJECTSTORE and not arr.base():
raise oefmt(self.space.w_NotImplementedError,
"cannot read object from array with no gc hook")
return self.box(self._read(arr.storage, i, offset))
diff --git a/pypy/module/pypyjit/test_pypy_c/test_import.py b/pypy/module/pypyjit/test_pypy_c/test_import.py
--- a/pypy/module/pypyjit/test_pypy_c/test_import.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_import.py
@@ -38,3 +38,27 @@
# call_may_force(absolute_import_with_lock).
for opname in log.opnames(loop.allops(opcode="IMPORT_NAME")):
assert 'call' not in opname # no call-like opcode
+
+ def test_import_fast_path(self, tmpdir):
+ print tmpdir
+ pkg = tmpdir.join('mypkg').ensure(dir=True)
+ subdir = pkg.join("sub").ensure(dir=True)
+ pkg.join('__init__.py').write("")
+ subdir.join('__init__.py').write("")
+ subdir.join('mod.py').write(str(py.code.Source("""
+ def do_the_import():
+ import sys
+ """)))
+ def main(path, n):
+ def do_the_import():
+ from mypkg.sub import mod
+ import sys
+ sys.path.append(path)
+ for i in range(n):
+ do_the_import()
+ #
+ log = self.run(main, [str(tmpdir), 300])
+ loop, = log.loops_by_filename(self.filepath)
+ # check that no string compares and other calls are there
+ for opname in log.opnames(loop.allops(opcode="IMPORT_NAME")):
+ assert 'call' not in opname # no call-like opcode
diff --git a/pypy/module/sys/version.py b/pypy/module/sys/version.py
--- a/pypy/module/sys/version.py
+++ b/pypy/module/sys/version.py
@@ -10,7 +10,7 @@
#XXX # sync CPYTHON_VERSION with patchlevel.h, package.py
CPYTHON_API_VERSION = 1013 #XXX # sync with include/modsupport.h
-PYPY_VERSION = (5, 4, 1, "alpha", 0) #XXX # sync patchlevel.h
+PYPY_VERSION = (5, 5, 0, "alpha", 0) #XXX # sync patchlevel.h
import pypy
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py b/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py
@@ -1415,6 +1415,7 @@
assert p.b == 12
assert p.c == 14
assert p.d == 14
+ py.test.raises(ValueError, ffi.new, "struct foo_s *", [0, 0, 0, 0])
def test_nested_field_offset_align(self):
ffi = FFI(backend=self.Backend())
@@ -1454,14 +1455,42 @@
assert p.b == 0
assert p.c == 14
assert p.d == 14
- p = ffi.new("union foo_u *", {'b': 12})
- assert p.a == 0
+ p = ffi.new("union foo_u *", {'a': -63, 'b': 12})
+ assert p.a == -63
assert p.b == 12
- assert p.c == 0
- assert p.d == 0
- # we cannot specify several items in the dict, even though
- # in theory in this particular case it would make sense
- # to give both 'a' and 'b'
+ assert p.c == -63
+ assert p.d == -63
+ p = ffi.new("union foo_u *", [123, 456])
+ assert p.a == 123
+ assert p.b == 456
+ assert p.c == 123
+ assert p.d == 123
+ py.test.raises(ValueError, ffi.new, "union foo_u *", [0, 0, 0])
+
+ def test_nested_anonymous_struct_2(self):
+ ffi = FFI(backend=self.Backend())
+ ffi.cdef("""
+ struct foo_s {
+ int a;
+ union { int b; union { int c, d; }; };
+ int e;
+ };
+ """)
+ assert ffi.sizeof("struct foo_s") == 3 * SIZE_OF_INT
+ p = ffi.new("struct foo_s *", [11, 22, 33])
+ assert p.a == 11
+ assert p.b == p.c == p.d == 22
+ assert p.e == 33
+ py.test.raises(ValueError, ffi.new, "struct foo_s *", [11, 22, 33, 44])
+ FOO = ffi.typeof("struct foo_s")
+ fields = [(name, fld.offset, fld.flags) for (name, fld) in FOO.fields]
+ assert fields == [
+ ('a', 0 * SIZE_OF_INT, 0),
+ ('b', 1 * SIZE_OF_INT, 0),
+ ('c', 1 * SIZE_OF_INT, 1),
+ ('d', 1 * SIZE_OF_INT, 1),
+ ('e', 2 * SIZE_OF_INT, 0),
+ ]
def test_cast_to_array_type(self):
ffi = FFI(backend=self.Backend())
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_ctypes.py b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_ctypes.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_ctypes.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_ctypes.py
@@ -35,6 +35,9 @@
def test_nested_anonymous_union(self):
py.test.skip("ctypes backend: not supported: nested anonymous union")
+ def test_nested_anonymous_struct_2(self):
+ py.test.skip("ctypes backend: not supported: nested anonymous union")
+
def test_CData_CType_2(self):
if sys.version_info >= (3,):
py.test.skip("ctypes backend: not supported in Python 3: CType")
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_zintegration.py b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_zintegration.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_zintegration.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_zintegration.py
@@ -154,7 +154,10 @@
from cffi.setuptools_ext import _set_py_limited_api
try:
import setuptools
- orig_version = setuptools.__version__
+ except ImportError as e:
+ py.test.skip(str(e))
+ orig_version = setuptools.__version__
+ try:
setuptools.__version__ = '26.0.0'
from setuptools import Extension
diff --git a/pypy/objspace/std/celldict.py b/pypy/objspace/std/celldict.py
--- a/pypy/objspace/std/celldict.py
+++ b/pypy/objspace/std/celldict.py
@@ -64,6 +64,8 @@
def setitem_str(self, w_dict, key, w_value):
cell = self.getdictvalue_no_unwrapping(w_dict, key)
+ #if (key == '__package__' or key == "__path__") and cell is not None and w_value is not cell:
+ # print "WARNING", key, w_value, cell, self
return self._setitem_str_cell_known(cell, w_dict, key, w_value)
def _setitem_str_cell_known(self, cell, w_dict, key, w_value):
diff --git a/pypy/objspace/std/memoryobject.py b/pypy/objspace/std/memoryobject.py
--- a/pypy/objspace/std/memoryobject.py
+++ b/pypy/objspace/std/memoryobject.py
@@ -26,6 +26,7 @@
"""Implement the built-in 'memoryview' type as a wrapper around
an interp-level buffer.
"""
+ _attrs_ = ['buf']
def __init__(self, buf, format=None, itemsize=1, ndim=-1,
shape=None, strides=None, suboffsets=None):
diff --git a/pypy/tool/release/repackage.sh b/pypy/tool/release/repackage.sh
--- a/pypy/tool/release/repackage.sh
+++ b/pypy/tool/release/repackage.sh
@@ -1,7 +1,7 @@
# Edit these appropriately before running this script
maj=5
min=4
-rev=0
+rev=1
branchname=release-$maj.x # ==OR== release-$maj.$min.x
tagname=release-pypy2.7-v$maj.$min.$rev # ==OR== release-$maj.$min
diff --git a/rpython/rlib/ropenssl.py b/rpython/rlib/ropenssl.py
--- a/rpython/rlib/ropenssl.py
+++ b/rpython/rlib/ropenssl.py
@@ -97,6 +97,21 @@
OPENSSL_VERSION_NUMBER = cconfig["OPENSSL_VERSION_NUMBER"]
HAVE_TLSv1_2 = OPENSSL_VERSION_NUMBER >= 0x10001000
+if OPENSSL_VERSION_NUMBER >= 0x10100000:
+ eci.pre_include_bits = ()
+ eci.post_include_bits = ()
+ raise Exception("""OpenSSL version >= 1.1 not supported yet.
+
+ This program requires OpenSSL version 1.0.x, and may also
+ work with LibreSSL or OpenSSL 0.9.x. OpenSSL 1.1 is quite
+ some work to update to; contributions are welcome. Sorry,
+ you need to install an older version of OpenSSL for now.
+ Make sure this older version is the one picked up by this
+ program when it runs the compiler.
+
+ This is the configuration used: %r""" % (eci,))
+
+
class CConfig:
_compilation_info_ = eci
diff --git a/rpython/rlib/runicode.py b/rpython/rlib/runicode.py
--- a/rpython/rlib/runicode.py
+++ b/rpython/rlib/runicode.py
@@ -1,5 +1,5 @@
import sys
-from rpython.rlib.objectmodel import specialize, we_are_translated
+from rpython.rlib.objectmodel import specialize, we_are_translated, enforceargs
from rpython.rlib.rstring import StringBuilder, UnicodeBuilder
from rpython.rlib.rarithmetic import r_uint, intmask, widen
from rpython.rlib.unicodedata import unicodedb
@@ -145,19 +145,21 @@
_invalid_byte_3_of_4 = _invalid_cont_byte
_invalid_byte_4_of_4 = _invalid_cont_byte
- at specialize.arg(2)
+ at enforceargs(allow_surrogates=bool)
def _invalid_byte_2_of_3(ordch1, ordch2, allow_surrogates):
return (ordch2>>6 != 0x2 or # 0b10
(ordch1 == 0xe0 and ordch2 < 0xa0)
# surrogates shouldn't be valid UTF-8!
- or (not allow_surrogates and ordch1 == 0xed and ordch2 > 0x9f))
+ or (ordch1 == 0xed and ordch2 > 0x9f and not allow_surrogates))
def _invalid_byte_2_of_4(ordch1, ordch2):
return (ordch2>>6 != 0x2 or # 0b10
(ordch1 == 0xf0 and ordch2 < 0x90) or
(ordch1 == 0xf4 and ordch2 > 0x8f))
- at specialize.arg(5)
+# note: this specialize() is here for rtyper/rstr.py, which calls this
+# function too but with its own fixed errorhandler
+ at specialize.arg_or_var(4)
def str_decode_utf_8_impl(s, size, errors, final, errorhandler,
allow_surrogates, result):
if size == 0:
@@ -330,6 +332,9 @@
return unicode_encode_utf_8_impl(s, size, errors, errorhandler,
allow_surrogates=allow_surrogates)
+# note: this specialize() is here for rtyper/rstr.py, which calls this
+# function too but with its own fixed errorhandler
+ at specialize.arg_or_var(3)
def unicode_encode_utf_8_impl(s, size, errors, errorhandler,
allow_surrogates=False):
assert(size >= 0)
diff --git a/rpython/rlib/test/test_runicode.py b/rpython/rlib/test/test_runicode.py
--- a/rpython/rlib/test/test_runicode.py
+++ b/rpython/rlib/test/test_runicode.py
@@ -55,7 +55,7 @@
s = s.encode(encoding)
except LookupError as e:
py.test.skip(e)
- result, consumed = decoder(s, len(s), True)
+ result, consumed = decoder(s, len(s), 'strict', final=True)
assert consumed == len(s)
self.typeequals(trueresult, result)
@@ -69,7 +69,7 @@
s = s.decode(encoding)
except LookupError as e:
py.test.skip(e)
- result = encoder(s, len(s), True)
+ result = encoder(s, len(s), 'strict')
self.typeequals(trueresult, result)
def checkencodeerror(self, s, encoding, start, stop):
@@ -823,9 +823,15 @@
def f(x):
s1 = "".join(["\xd7\x90\xd6\x96\xeb\x96\x95\xf0\x90\x91\x93"] * x)
- u, consumed = runicode.str_decode_utf_8(s1, len(s1), True)
- s2 = runicode.unicode_encode_utf_8(u, len(u), True)
- return s1 == s2
+ u, consumed = runicode.str_decode_utf_8(s1, len(s1), 'strict',
+ allow_surrogates=True)
+ s2 = runicode.unicode_encode_utf_8(u, len(u), 'strict',
+ allow_surrogates=True)
+ u3, consumed3 = runicode.str_decode_utf_8(s1, len(s1), 'strict',
+ allow_surrogates=False)
+ s3 = runicode.unicode_encode_utf_8(u3, len(u3), 'strict',
+ allow_surrogates=False)
+ return s1 == s2 == s3
res = interpret(f, [2])
assert res
diff --git a/rpython/rtyper/rstr.py b/rpython/rtyper/rstr.py
--- a/rpython/rtyper/rstr.py
+++ b/rpython/rtyper/rstr.py
@@ -30,12 +30,13 @@
assert value is not None
result = UnicodeBuilder(len(value))
self.rstr_decode_utf_8(
- value, len(value), 'strict', final=False,
+ value, len(value), 'strict', final=True,
errorhandler=self.ll_raise_unicode_exception_decode,
allow_surrogates=False, result=result)
return self.ll.llunicode(result.build())
- def ll_raise_unicode_exception_decode(self, errors, encoding, msg, s,
+ @staticmethod
+ def ll_raise_unicode_exception_decode(errors, encoding, msg, s,
startingpos, endingpos):
raise UnicodeDecodeError(encoding, s, startingpos, endingpos, msg)
@@ -411,7 +412,8 @@
allow_surrogates=False)
return self.ll.llstr(bytes)
- def ll_raise_unicode_exception_encode(self, errors, encoding, msg, u,
+ @staticmethod
+ def ll_raise_unicode_exception_encode(errors, encoding, msg, u,
startingpos, endingpos):
raise UnicodeEncodeError(encoding, u, startingpos, endingpos, msg)
diff --git a/rpython/rtyper/test/test_runicode.py b/rpython/rtyper/test/test_runicode.py
--- a/rpython/rtyper/test/test_runicode.py
+++ b/rpython/rtyper/test/test_runicode.py
@@ -162,6 +162,18 @@
assert self.ll_to_string(self.interpret(f, [0])) == f(0)
+ def test_unicode_decode_final(self):
+ strings = ['\xc3', '']
+ def f(n):
+ try:
+ strings[n].decode('utf-8')
+ except UnicodeDecodeError:
+ return True
+ return False
+
+ assert f(0)
+ assert self.interpret(f, [0])
+
def test_utf_8_decoding_annotation(self):
from rpython.rlib.runicode import str_decode_utf_8
def errorhandler(errors, encoding, msg, s,
More information about the pypy-commit
mailing list