[pypy-commit] pypy py3k: hg merge default
rlamy
pypy.commits at gmail.com
Fri Jun 3 21:58:47 EDT 2016
Author: Ronan Lamy <ronan.lamy at gmail.com>
Branch: py3k
Changeset: r84916:ef5a7f148b27
Date: 2016-06-04 02:58 +0100
http://bitbucket.org/pypy/pypy/changeset/ef5a7f148b27/
Log: hg merge default
Port cpyext changes to bytearray
diff --git a/lib_pypy/cffi/api.py b/lib_pypy/cffi/api.py
--- a/lib_pypy/cffi/api.py
+++ b/lib_pypy/cffi/api.py
@@ -332,8 +332,8 @@
def from_buffer(self, python_buffer):
"""Return a <cdata 'char[]'> that points to the data of the
given Python object, which must support the buffer interface.
- Note that this is not meant to be used on the built-in types str,
- unicode, or bytearray (you can build 'char[]' arrays explicitly)
+ Note that this is not meant to be used on the built-in types
+ str or unicode (you can build 'char[]' arrays explicitly)
but only on objects containing large quantities of raw data
in some other format, like 'array.array' or numpy arrays.
"""
diff --git a/lib_pypy/cffi/recompiler.py b/lib_pypy/cffi/recompiler.py
--- a/lib_pypy/cffi/recompiler.py
+++ b/lib_pypy/cffi/recompiler.py
@@ -814,7 +814,7 @@
try:
if ftype.is_integer_type() or fbitsize >= 0:
# accept all integers, but complain on float or double
- prnt(" (void)((p->%s) << 1); /* check that '%s.%s' is "
+ prnt(" (void)((p->%s) | 0); /* check that '%s.%s' is "
"an integer */" % (fname, cname, fname))
continue
# only accept exactly the type declared, except that '[]'
@@ -991,7 +991,7 @@
prnt('static int %s(unsigned long long *o)' % funcname)
prnt('{')
prnt(' int n = (%s) <= 0;' % (name,))
- prnt(' *o = (unsigned long long)((%s) << 0);'
+ prnt(' *o = (unsigned long long)((%s) | 0);'
' /* check that %s is an integer */' % (name, name))
if check_value is not None:
if check_value > 0:
@@ -1250,7 +1250,7 @@
def _emit_bytecode_UnknownIntegerType(self, tp, index):
s = ('_cffi_prim_int(sizeof(%s), (\n'
- ' ((%s)-1) << 0 /* check that %s is an integer type */\n'
+ ' ((%s)-1) | 0 /* check that %s is an integer type */\n'
' ) <= 0)' % (tp.name, tp.name, tp.name))
self.cffi_types[index] = CffiOp(OP_PRIMITIVE, s)
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
@@ -131,3 +131,15 @@
Enable pickling of W_PyCFunctionObject by monkeypatching pickle.Pickler.dispatch
at cpyext import time
+
+.. branch: nonmovable-list
+
+Add a way to ask "give me a raw pointer to this list's
+items". Only for resizable lists of primitives. Turns the GcArray
+nonmovable, possibly making a copy of it first.
+
+.. branch: cpyext-ext
+
+Finish the work already partially merged in cpyext-for-merge. Adds support
+for ByteArrayObject using the nonmovable-list, which also enables
+buffer(bytearray(<some-list>))
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -251,6 +251,9 @@
def identifier_w(self, space):
self._typed_unwrap_error(space, "string")
+ def bytearray_list_of_chars_w(self, space):
+ self._typed_unwrap_error(space, "bytearray")
+
def int_w(self, space, allow_conversion=True):
# note that W_IntObject.int_w has a fast path and W_FloatObject.int_w
# raises w_TypeError
diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py
--- a/pypy/interpreter/typedef.py
+++ b/pypy/interpreter/typedef.py
@@ -23,6 +23,7 @@
else:
bases = [__base]
self.bases = bases
+ # Used in cpyext to fill tp_as_buffer slots
assert __buffer in {None, 'read-write', 'read'}, "Unknown value for __buffer"
self.buffer = __buffer
self.heaptype = False
diff --git a/pypy/module/_cffi_backend/cdataobj.py b/pypy/module/_cffi_backend/cdataobj.py
--- a/pypy/module/_cffi_backend/cdataobj.py
+++ b/pypy/module/_cffi_backend/cdataobj.py
@@ -222,24 +222,43 @@
w_value.get_array_length() == length):
# fast path: copying from exactly the correct type
with w_value as source:
- rffi.c_memcpy(target, source, ctitemsize * length)
+ source = rffi.cast(rffi.VOIDP, source)
+ target = rffi.cast(rffi.VOIDP, target)
+ size = rffi.cast(rffi.SIZE_T, ctitemsize * length)
+ rffi.c_memcpy(target, source, size)
return
#
- # A fast path for <char[]>[0:N] = "somestring".
+ # A fast path for <char[]>[0:N] = "somestring" or some bytearray.
from pypy.module._cffi_backend import ctypeprim
space = self.space
- if (space.isinstance_w(w_value, space.w_str) and
- isinstance(ctitem, ctypeprim.W_CTypePrimitiveChar)):
- from rpython.rtyper.annlowlevel import llstr
- from rpython.rtyper.lltypesystem.rstr import copy_string_to_raw
- value = space.str_w(w_value)
- if len(value) != length:
- raise oefmt(space.w_ValueError,
- "need a string of length %d, got %d",
- length, len(value))
- copy_string_to_raw(llstr(value), target, 0, length)
- return
+ if isinstance(ctitem, ctypeprim.W_CTypePrimitive) and ctitem.size == 1:
+ if space.isinstance_w(w_value, space.w_str):
+ from rpython.rtyper.annlowlevel import llstr
+ from rpython.rtyper.lltypesystem.rstr import copy_string_to_raw
+ value = space.str_w(w_value)
+ if len(value) != length:
+ raise oefmt(space.w_ValueError,
+ "need a string of length %d, got %d",
+ length, len(value))
+ copy_string_to_raw(llstr(value), target, 0, length)
+ return
+ if space.isinstance_w(w_value, space.w_bytearray):
+ value = w_value.bytearray_list_of_chars_w(space)
+ if len(value) != length:
+ raise oefmt(space.w_ValueError,
+ "need a bytearray of length %d, got %d",
+ length, len(value))
+ self._copy_list_of_chars_to_raw(value, target, length)
+ return
#
+ self._do_setslice_iterate(space, ctitem, w_value, target, ctitemsize,
+ length)
+
+ @staticmethod
+ def _do_setslice_iterate(space, ctitem, w_value, target, ctitemsize,
+ length):
+ # general case, contains a loop
+ # (XXX is it worth adding a jitdriver here?)
w_iter = space.iter(w_value)
for i in range(length):
try:
@@ -260,6 +279,12 @@
raise oefmt(space.w_ValueError,
"got more than %d values to unpack", length)
+ @staticmethod
+ def _copy_list_of_chars_to_raw(value, target, length):
+ # contains a loop, moved out of _do_setslice()
+ for i in range(length):
+ target[i] = value[i]
+
def _add_or_sub(self, w_other, sign):
space = self.space
i = sign * space.getindex_w(w_other, space.w_OverflowError)
diff --git a/pypy/module/_cffi_backend/ctypeobj.py b/pypy/module/_cffi_backend/ctypeobj.py
--- a/pypy/module/_cffi_backend/ctypeobj.py
+++ b/pypy/module/_cffi_backend/ctypeobj.py
@@ -43,9 +43,6 @@
else:
return 'NULL'
- def is_char_ptr_or_array(self):
- return False
-
def is_unichar_ptr_or_array(self):
return False
diff --git a/pypy/module/_cffi_backend/ctypeptr.py b/pypy/module/_cffi_backend/ctypeptr.py
--- a/pypy/module/_cffi_backend/ctypeptr.py
+++ b/pypy/module/_cffi_backend/ctypeptr.py
@@ -31,9 +31,6 @@
self.ctitem = ctitem
self.can_cast_anything = could_cast_anything and ctitem.cast_anything
- def is_char_ptr_or_array(self):
- return isinstance(self.ctitem, ctypeprim.W_CTypePrimitiveChar)
-
def is_unichar_ptr_or_array(self):
return isinstance(self.ctitem, ctypeprim.W_CTypePrimitiveUniChar)
@@ -56,12 +53,8 @@
value = rffi.cast(rffi.CCHARP, value)
return cdataobj.W_CData(space, value, self)
- def _convert_array_from_listview(self, cdata, w_ob):
- if self.ctitem.pack_list_of_items(cdata, w_ob): # fast path
- return
- #
+ def _convert_array_from_listview(self, cdata, lst_w):
space = self.space
- lst_w = space.listview(w_ob)
if self.length >= 0 and len(lst_w) > self.length:
raise oefmt(space.w_IndexError,
"too many initializers for '%s' (got %d)",
@@ -75,7 +68,10 @@
space = self.space
if (space.isinstance_w(w_ob, space.w_list) or
space.isinstance_w(w_ob, space.w_tuple)):
- self._convert_array_from_listview(cdata, w_ob)
+ if self.ctitem.pack_list_of_items(cdata, w_ob): # fast path
+ pass
+ else:
+ self._convert_array_from_listview(cdata, space.listview(w_ob))
elif (self.can_cast_anything or
(self.ctitem.is_primitive_integer and
self.ctitem.size == rffi.sizeof(lltype.Char))):
diff --git a/pypy/module/_cffi_backend/ffi_obj.py b/pypy/module/_cffi_backend/ffi_obj.py
--- a/pypy/module/_cffi_backend/ffi_obj.py
+++ b/pypy/module/_cffi_backend/ffi_obj.py
@@ -347,7 +347,7 @@
"""\
Return a <cdata 'char[]'> that points to the data of the given Python
object, which must support the buffer interface. Note that this is
-not meant to be used on the built-in types str, unicode, or bytearray
+not meant to be used on the built-in types str or unicode
(you can build 'char[]' arrays explicitly) but only on objects
containing large quantities of raw data in some other format, like
'array.array' or numpy arrays."""
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
@@ -2686,10 +2686,19 @@
BCharArray = new_array_type(
new_pointer_type(new_primitive_type("char")), None)
py.test.raises(TypeError, newp, BCharArray, bytearray(b"foo"))
- p = newp(BCharArray, 4)
- buffer(p)[:] = bytearray(b"foo\x00")
- assert len(p) == 4
- assert list(p) == [b"f", b"o", b"o", b"\x00"]
+ p = newp(BCharArray, 5)
+ buffer(p)[:] = bytearray(b"foo.\x00")
+ assert len(p) == 5
+ assert list(p) == [b"f", b"o", b"o", b".", b"\x00"]
+ p[1:3] = bytearray(b"XY")
+ assert list(p) == [b"f", b"X", b"Y", b".", b"\x00"]
+
+def test_string_assignment_to_byte_array():
+ BByteArray = new_array_type(
+ new_pointer_type(new_primitive_type("unsigned char")), None)
+ p = newp(BByteArray, 5)
+ p[0:3] = bytearray(b"XYZ")
+ assert list(p) == [ord("X"), ord("Y"), ord("Z"), 0, 0]
# XXX hack
if sys.version_info >= (3,):
@@ -3317,13 +3326,12 @@
cast(p, c)[1] += 500
assert list(a) == [10000, 20500, 30000]
-def test_from_buffer_not_str_unicode_bytearray():
+def test_from_buffer_not_str_unicode():
BChar = new_primitive_type("char")
BCharP = new_pointer_type(BChar)
BCharA = new_array_type(BCharP, None)
py.test.raises(TypeError, from_buffer, BCharA, b"foo")
py.test.raises(TypeError, from_buffer, BCharA, u+"foo")
- py.test.raises(TypeError, from_buffer, BCharA, bytearray(b"foo"))
try:
from __builtin__ import buffer
except ImportError:
@@ -3331,16 +3339,27 @@
else:
py.test.raises(TypeError, from_buffer, BCharA, buffer(b"foo"))
py.test.raises(TypeError, from_buffer, BCharA, buffer(u+"foo"))
- py.test.raises(TypeError, from_buffer, BCharA,
- buffer(bytearray(b"foo")))
try:
from __builtin__ import memoryview
except ImportError:
pass
else:
py.test.raises(TypeError, from_buffer, BCharA, memoryview(b"foo"))
- py.test.raises(TypeError, from_buffer, BCharA,
- memoryview(bytearray(b"foo")))
+
+def test_from_buffer_bytearray():
+ a = bytearray(b"xyz")
+ BChar = new_primitive_type("char")
+ BCharP = new_pointer_type(BChar)
+ BCharA = new_array_type(BCharP, None)
+ p = from_buffer(BCharA, a)
+ assert typeof(p) is BCharA
+ assert len(p) == 3
+ assert repr(p) == "<cdata 'char[]' buffer len 3 from 'bytearray' object>"
+ assert p[2] == b"z"
+ p[2] = b"."
+ assert a[2] == ord(".")
+ a[2] = ord("?")
+ assert p[2] == b"?"
def test_from_buffer_more_cases():
try:
diff --git a/pypy/module/cpyext/__init__.py b/pypy/module/cpyext/__init__.py
--- a/pypy/module/cpyext/__init__.py
+++ b/pypy/module/cpyext/__init__.py
@@ -42,6 +42,7 @@
import pypy.module.cpyext.typeobject
import pypy.module.cpyext.object
import pypy.module.cpyext.bytesobject
+import pypy.module.cpyext.bytearrayobject
import pypy.module.cpyext.tupleobject
import pypy.module.cpyext.setobject
import pypy.module.cpyext.dictobject
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
@@ -1433,7 +1433,7 @@
prefix=prefix)
code = "#include <Python.h>\n"
if use_micronumpy:
- code += "#include <pypy_numpy.h> /* api.py line 1290 */"
+ code += "#include <pypy_numpy.h> /* api.py line 1290 */\n"
code += "\n".join(functions)
eci = build_eci(False, export_symbols, code, use_micronumpy)
diff --git a/pypy/module/cpyext/bytearrayobject.py b/pypy/module/cpyext/bytearrayobject.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/bytearrayobject.py
@@ -0,0 +1,134 @@
+from rpython.rtyper.lltypesystem import rffi, lltype
+from rpython.rlib.objectmodel import specialize, we_are_translated
+from pypy.interpreter.error import OperationError, oefmt
+from pypy.objspace.std.bytearrayobject import new_bytearray
+from pypy.module.cpyext.api import (
+ cpython_api, cpython_struct, bootstrap_function, build_type_checkers,
+ PyVarObjectFields, Py_ssize_t, CONST_STRING, CANNOT_FAIL)
+from pypy.module.cpyext.pyerrors import PyErr_BadArgument
+from pypy.module.cpyext.pyobject import (
+ PyObject, PyObjectP, Py_DecRef, make_ref, from_ref, track_reference,
+ make_typedescr, get_typedescr, Py_IncRef)
+# Type PyByteArrayObject represents a mutable array of bytes.
+# The Python API is that of a sequence;
+# the bytes are mapped to ints in [0, 256).
+# Bytes are not characters; they may be used to encode characters.
+# The only way to go between bytes and str/unicode is via encoding
+# and decoding.
+# For the convenience of C programmers, the bytes type is considered
+# to contain a char pointer, not an unsigned char pointer.
+
+# Expose data as a rw cchar* only through PyByteArray_AsString
+# Under this strategy the pointer could loose its synchronization with
+# the underlying space.w_bytearray if PyByteArray_Resize is called, so
+# hopefully the use of the pointer is short-lived
+
+PyByteArrayObjectStruct = lltype.ForwardReference()
+PyByteArrayObject = lltype.Ptr(PyByteArrayObjectStruct)
+PyByteArrayObjectFields = PyVarObjectFields
+# (("ob_exports", rffi.INT), ("ob_alloc", rffi.LONG), ("ob_bytes", rffi.CCHARP))
+cpython_struct("PyByteArrayObject", PyByteArrayObjectFields, PyByteArrayObjectStruct)
+
+ at bootstrap_function
+def init_bytearrayobject(space):
+ "Type description of PyByteArrayObject"
+ #make_typedescr(space.w_bytearray.layout.typedef,
+ # basestruct=PyByteArrayObject.TO,
+ # attach=bytearray_attach,
+ # dealloc=bytearray_dealloc,
+ # realize=bytearray_realize)
+
+PyByteArray_Check, PyByteArray_CheckExact = build_type_checkers("ByteArray", "w_bytearray")
+
+# XXX dead code to be removed
+#def bytearray_attach(space, py_obj, w_obj):
+# """
+# Fills a newly allocated PyByteArrayObject with the given bytearray object
+# """
+# py_ba = rffi.cast(PyByteArrayObject, py_obj)
+# py_ba.c_ob_size = len(space.str_w(w_obj))
+# py_ba.c_ob_bytes = lltype.nullptr(rffi.CCHARP.TO)
+# py_ba.c_ob_exports = rffi.cast(rffi.INT, 0)
+
+#def bytearray_realize(space, py_obj):
+# """
+# Creates the bytearray in the interpreter.
+# """
+# py_ba = rffi.cast(PyByteArrayObject, py_obj)
+# if not py_ba.c_ob_bytes:
+# py_ba.c_buffer = lltype.malloc(rffi.CCHARP.TO, py_ba.c_ob_size + 1,
+# flavor='raw', zero=True)
+# s = rffi.charpsize2str(py_ba.c_ob_bytes, py_ba.c_ob_size)
+# w_obj = space.wrap(s)
+# py_ba.c_ob_exports = rffi.cast(rffi.INT, 0)
+# track_reference(space, py_obj, w_obj)
+# return w_obj
+
+#@cpython_api([PyObject], lltype.Void, header=None)
+#def bytearray_dealloc(space, py_obj):
+# """Frees allocated PyByteArrayObject resources.
+# """
+# py_ba = rffi.cast(PyByteArrayObject, py_obj)
+# if py_ba.c_ob_bytes:
+# lltype.free(py_ba.c_ob_bytes, flavor="raw")
+# from pypy.module.cpyext.object import PyObject_dealloc
+# PyObject_dealloc(space, py_obj)
+
+#_______________________________________________________________________
+
+ at cpython_api([PyObject], PyObject, result_is_ll=True)
+def PyByteArray_FromObject(space, w_obj):
+ """Return a new bytearray object from any object, o, that implements the
+ buffer protocol.
+
+ XXX expand about the buffer protocol, at least somewhere"""
+ w_buffer = space.call_function(space.w_bytearray, w_obj)
+ return make_ref(space, w_buffer)
+
+ at cpython_api([rffi.CCHARP, Py_ssize_t], PyObject, result_is_ll=True)
+def PyByteArray_FromStringAndSize(space, char_p, length):
+ """Create a new bytearray object from string and its length, len. On
+ failure, NULL is returned."""
+ if char_p:
+ w_s = space.wrapbytes(rffi.charpsize2str(char_p, length))
+ else:
+ w_s = space.newint(length)
+ w_buffer = space.call_function(space.w_bytearray, w_s)
+ return make_ref(space, w_buffer)
+
+ at cpython_api([PyObject, PyObject], PyObject)
+def PyByteArray_Concat(space, w_left, w_right):
+ """Concat bytearrays a and b and return a new bytearray with the result."""
+ return space.add(w_left, w_right)
+
+ at cpython_api([PyObject], Py_ssize_t, error=-1)
+def PyByteArray_Size(space, w_obj):
+ """Return the size of bytearray after checking for a NULL pointer."""
+ if not w_obj:
+ return 0
+ return space.len_w(w_obj)
+
+ at cpython_api([PyObject], rffi.CCHARP, error=0)
+def PyByteArray_AsString(space, w_obj):
+ """Return the contents of bytearray as a char array after checking for a
+ NULL pointer."""
+ if space.isinstance_w(w_obj, space.w_bytearray):
+ return w_obj.nonmovable_carray(space)
+ else:
+ raise oefmt(space.w_TypeError,
+ "expected bytearray object, %T found", w_obj)
+
+ at cpython_api([PyObject, Py_ssize_t], rffi.INT_real, error=-1)
+def PyByteArray_Resize(space, w_obj, newlen):
+ """Resize the internal buffer of bytearray to len."""
+ if space.isinstance_w(w_obj, space.w_bytearray):
+ oldlen = space.len_w(w_obj)
+ if newlen > oldlen:
+ space.call_method(w_obj, 'extend', space.wrapbytes('\x00' * (newlen - oldlen)))
+ elif oldlen > newlen:
+ assert newlen >= 0
+ space.delslice(w_obj, space.wrap(newlen), space.wrap(oldlen))
+ return 0
+ else:
+ raise oefmt(space.w_TypeError,
+ "expected bytearray object, %T found", w_obj)
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
@@ -2,7 +2,7 @@
from rpython.rtyper.lltypesystem import rffi, lltype
from pypy.module.cpyext.api import (
cpython_api, cpython_struct, bootstrap_function, build_type_checkers,
- PyObjectFields, PyVarObjectFields, Py_ssize_t, CONST_STRING, CANNOT_FAIL)
+ PyVarObjectFields, Py_ssize_t, CONST_STRING, CANNOT_FAIL)
from pypy.module.cpyext.pyerrors import PyErr_BadArgument
from pypy.module.cpyext.pyobject import (
PyObject, PyObjectP, Py_DecRef, make_ref, from_ref, track_reference,
diff --git a/pypy/module/cpyext/include/Python.h b/pypy/module/cpyext/include/Python.h
--- a/pypy/module/cpyext/include/Python.h
+++ b/pypy/module/cpyext/include/Python.h
@@ -114,6 +114,7 @@
#include "pythonrun.h"
#include "pyerrors.h"
#include "sysmodule.h"
+#include "bytearrayobject.h"
#include "descrobject.h"
#include "tupleobject.h"
#include "dictobject.h"
diff --git a/pypy/module/cpyext/include/bytearrayobject.h b/pypy/module/cpyext/include/bytearrayobject.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/include/bytearrayobject.h
@@ -0,0 +1,36 @@
+/* ByteArray object interface */
+
+#ifndef Py_BYTEARRAYOBJECT_H
+#define Py_BYTEARRAYOBJECT_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdarg.h>
+
+/* Type PyByteArrayObject represents a mutable array of bytes.
+ * The Python API is that of a sequence;
+ * the bytes are mapped to ints in [0, 256).
+ * Bytes are not characters; they may be used to encode characters.
+ * The only way to go between bytes and str/unicode is via encoding
+ * and decoding.
+ * While CPython exposes interfaces to this object, pypy does not
+ */
+
+#define PyByteArray_GET_SIZE(op) PyByteArray_Size((PyObject*)(op))
+#define PyByteArray_AS_STRING(op) PyByteArray_AsString((PyObject*)(op))
+
+/* Object layout */
+typedef struct {
+ PyObject_VAR_HEAD
+#if 0
+ int ob_exports; /* how many buffer exports */
+ Py_ssize_t ob_alloc; /* How many bytes allocated */
+ char *ob_bytes;
+#endif
+} PyByteArrayObject;
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !Py_BYTEARRAYOBJECT_H */
diff --git a/pypy/module/cpyext/include/bytesobject.h b/pypy/module/cpyext/include/bytesobject.h
--- a/pypy/module/cpyext/include/bytesobject.h
+++ b/pypy/module/cpyext/include/bytesobject.h
@@ -61,9 +61,6 @@
#define PyString_CHECK_INTERNED(op) (((PyStringObject *)(op))->ob_sstate)
-#define PyByteArray_Check(obj) \
- PyObject_IsInstance(obj, (PyObject *)&PyByteArray_Type)
-
#ifdef __cplusplus
}
#endif
diff --git a/pypy/module/cpyext/stubs.py b/pypy/module/cpyext/stubs.py
--- a/pypy/module/cpyext/stubs.py
+++ b/pypy/module/cpyext/stubs.py
@@ -41,57 +41,6 @@
raise NotImplementedError
@cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL)
-def PyByteArray_CheckExact(space, o):
- """Return true if the object o is a bytearray object, but not an instance of a
- subtype of the bytearray type."""
- raise NotImplementedError
-
- at cpython_api([PyObject], PyObject)
-def PyByteArray_FromObject(space, o):
- """Return a new bytearray object from any object, o, that implements the
- buffer protocol.
-
- XXX expand about the buffer protocol, at least somewhere"""
- raise NotImplementedError
-
- at cpython_api([rffi.CCHARP, Py_ssize_t], PyObject)
-def PyByteArray_FromStringAndSize(space, string, len):
- """Create a new bytearray object from string and its length, len. On
- failure, NULL is returned."""
- raise NotImplementedError
-
- at cpython_api([PyObject, PyObject], PyObject)
-def PyByteArray_Concat(space, a, b):
- """Concat bytearrays a and b and return a new bytearray with the result."""
- raise NotImplementedError
-
- at cpython_api([PyObject], Py_ssize_t, error=-1)
-def PyByteArray_Size(space, bytearray):
- """Return the size of bytearray after checking for a NULL pointer."""
- raise NotImplementedError
-
- at cpython_api([PyObject], rffi.CCHARP)
-def PyByteArray_AsString(space, bytearray):
- """Return the contents of bytearray as a char array after checking for a
- NULL pointer."""
- raise NotImplementedError
-
- at cpython_api([PyObject, Py_ssize_t], rffi.INT_real, error=-1)
-def PyByteArray_Resize(space, bytearray, len):
- """Resize the internal buffer of bytearray to len."""
- raise NotImplementedError
-
- at cpython_api([PyObject], rffi.CCHARP)
-def PyByteArray_AS_STRING(space, bytearray):
- """Macro version of PyByteArray_AsString()."""
- raise NotImplementedError
-
- at cpython_api([PyObject], Py_ssize_t, error=-1)
-def PyByteArray_GET_SIZE(space, bytearray):
- """Macro version of PyByteArray_Size()."""
- raise NotImplementedError
-
- at cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL)
def PyCell_Check(space, ob):
"""Return true if ob is a cell object; ob must not be NULL."""
raise NotImplementedError
diff --git a/pypy/module/cpyext/test/test_bytearrayobject.py b/pypy/module/cpyext/test/test_bytearrayobject.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/test/test_bytearrayobject.py
@@ -0,0 +1,198 @@
+from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
+
+class AppTestStringObject(AppTestCpythonExtensionBase):
+ def test_basic(self):
+ module = self.import_extension('foo', [
+ ("get_hello1", "METH_NOARGS",
+ """
+ return PyByteArray_FromStringAndSize(
+ "Hello world<should not be included>", 11);
+ """),
+ ("get_hello2", "METH_NOARGS",
+ """
+ return PyByteArray_FromStringAndSize("Hello world", 12);
+ """),
+ ("test_Size", "METH_NOARGS",
+ """
+ PyObject* s = PyByteArray_FromStringAndSize("Hello world", 12);
+ int result = 0;
+ size_t expected_size;
+
+ if(PyByteArray_Size(s) == 12) {
+ result = 1;
+ }
+ #ifdef PYPY_VERSION
+ expected_size = sizeof(void*)*3;
+ #elif defined Py_DEBUG
+ expected_size = 64;
+ #else
+ expected_size = 48;
+ #endif
+ if(s->ob_type->tp_basicsize != expected_size)
+ {
+ printf("tp_basicsize==%ld\\n", s->ob_type->tp_basicsize);
+ result = 0;
+ }
+ Py_DECREF(s);
+ return PyBool_FromLong(result);
+ """),
+ ("test_is_bytearray", "METH_VARARGS",
+ """
+ return PyBool_FromLong(PyByteArray_Check(PyTuple_GetItem(args, 0)));
+ """)], prologue='#include <stdlib.h>')
+ assert module.get_hello1() == b'Hello world'
+ assert module.get_hello2() == b'Hello world\x00'
+ assert module.test_Size()
+ assert module.test_is_bytearray(bytearray(b""))
+ assert not module.test_is_bytearray(())
+
+ def test_bytearray_buffer_init(self):
+ module = self.import_extension('foo', [
+ ("getbytearray", "METH_NOARGS",
+ """
+ PyObject *s, *t;
+ char* c;
+ Py_ssize_t len;
+
+ s = PyByteArray_FromStringAndSize(NULL, 4);
+ if (s == NULL)
+ return NULL;
+ t = PyByteArray_FromStringAndSize(NULL, 3);
+ if (t == NULL)
+ return NULL;
+ Py_DECREF(t);
+ c = PyByteArray_AsString(s);
+ if (c == NULL)
+ {
+ PyErr_SetString(PyExc_ValueError, "non-null bytearray object expected");
+ return NULL;
+ }
+ c[0] = 'a';
+ c[1] = 'b';
+ c[2] = 0;
+ c[3] = 'c';
+ return s;
+ """),
+ ])
+ s = module.getbytearray()
+ assert len(s) == 4
+ assert s == b'ab\x00c'
+
+ def test_bytearray_mutable(self):
+ module = self.import_extension('foo', [
+ ("mutable", "METH_NOARGS",
+ """
+ PyObject *base;
+ char * p_str;
+ base = PyByteArray_FromStringAndSize("test", 10);
+ if (PyByteArray_GET_SIZE(base) != 10)
+ return PyLong_FromLong(-PyByteArray_GET_SIZE(base));
+ memcpy(PyByteArray_AS_STRING(base), "works", 6);
+ Py_INCREF(base);
+ return base;
+ """),
+ ])
+ s = module.mutable()
+ if s == b'\x00' * 10:
+ assert False, "no RW access to bytearray"
+ assert s[:6] == b'works\x00'
+
+ def test_AsByteArray(self):
+ module = self.import_extension('foo', [
+ ("getbytearray", "METH_NOARGS",
+ """
+ PyObject* s1 = PyByteArray_FromStringAndSize("test", 4);
+ if (s1 == NULL)
+ return NULL;
+ char* c = PyByteArray_AsString(s1);
+ PyObject* s2 = PyByteArray_FromStringAndSize(c, 4);
+ Py_DECREF(s1);
+ return s2;
+ """),
+ ])
+ s = module.getbytearray()
+ assert s == b'test'
+
+ def test_manipulations(self):
+ module = self.import_extension('foo', [
+ ("bytearray_from_bytes", "METH_VARARGS",
+ '''
+ return PyByteArray_FromStringAndSize(PyBytes_AsString(
+ PyTuple_GetItem(args, 0)), 4);
+ '''
+ ),
+ ("bytes_from_bytearray", "METH_VARARGS",
+ '''
+ char * buf;
+ int n;
+ PyObject * obj;
+ obj = PyTuple_GetItem(args, 0);
+ buf = PyByteArray_AsString(obj);
+ if (buf == NULL)
+ {
+ PyErr_SetString(PyExc_ValueError, "non-null bytearray object expected");
+ return NULL;
+ }
+ n = PyByteArray_Size(obj);
+ return PyBytes_FromStringAndSize(buf, n);
+ '''
+ ),
+ ("concat", "METH_VARARGS",
+ """
+ PyObject * ret, *right, *left;
+ PyObject *ba1, *ba2;
+ if (!PyArg_ParseTuple(args, "OO", &left, &right)) {
+ return PyUnicode_FromString("parse failed");
+ }
+ ba1 = PyByteArray_FromObject(left);
+ ba2 = PyByteArray_FromObject(right);
+ if (ba1 == NULL || ba2 == NULL)
+ {
+ /* exception should be set */
+ return NULL;
+ }
+ ret = PyByteArray_Concat(ba1, ba2);
+ return ret;
+ """)])
+ assert module.bytearray_from_bytes(b"huheduwe") == b"huhe"
+ assert module.bytes_from_bytearray(bytearray(b'abc')) == b'abc'
+ raises(ValueError, module.bytes_from_bytearray, 4.0)
+ ret = module.concat(b'abc', b'def')
+ assert ret == b'abcdef'
+ assert not isinstance(ret, str)
+ assert isinstance(ret, bytearray)
+ raises(TypeError, module.concat, b'abc', u'def')
+
+ def test_bytearray_resize(self):
+ module = self.import_extension('foo', [
+ ("bytearray_resize", "METH_VARARGS",
+ '''
+ PyObject *obj, *ba;
+ int newsize, oldsize, ret;
+ if (!PyArg_ParseTuple(args, "Oi", &obj, &newsize)) {
+ return PyUnicode_FromString("parse failed");
+ }
+
+ ba = PyByteArray_FromObject(obj);
+ if (ba == NULL)
+ return NULL;
+ oldsize = PyByteArray_Size(ba);
+ if (oldsize == 0)
+ {
+ return PyUnicode_FromString("oldsize is 0");
+ }
+ ret = PyByteArray_Resize(ba, newsize);
+ if (ret != 0)
+ {
+ printf("ret, oldsize, newsize= %d, %d, %d\\n", ret, oldsize, newsize);
+ return NULL;
+ }
+ return ba;
+ '''
+ )])
+ ret = module.bytearray_resize(b'abc', 6)
+ assert len(ret) == 6,"%s, len=%d" % (ret, len(ret))
+ assert ret == b'abc\x00\x00\x00'
+ ret = module.bytearray_resize(b'abcdefghi', 4)
+ assert len(ret) == 4,"%s, len=%d" % (ret, len(ret))
+ assert ret == b'abcd'
diff --git a/pypy/module/cpyext/test/test_getargs.py b/pypy/module/cpyext/test/test_getargs.py
--- a/pypy/module/cpyext/test/test_getargs.py
+++ b/pypy/module/cpyext/test/test_getargs.py
@@ -123,7 +123,8 @@
return result;
''')
assert b'foo\0bar\0baz' == pybuffer(b'foo\0bar\0baz')
-
+ return # XXX
+ assert b'foo\0bar\0baz' == pybuffer(bytearray(b'foo\0bar\0baz'))
def test_pyarg_parse_string_fails(self):
"""
diff --git a/pypy/module/cpyext/test/test_typeobject.py b/pypy/module/cpyext/test/test_typeobject.py
--- a/pypy/module/cpyext/test/test_typeobject.py
+++ b/pypy/module/cpyext/test/test_typeobject.py
@@ -5,8 +5,8 @@
from pypy.module.cpyext.pyobject import make_ref, from_ref
from pypy.module.cpyext.typeobject import PyTypeObjectPtr
+import sys
import pytest
-import sys
class AppTestTypeObject(AppTestCpythonExtensionBase):
def test_typeobject(self):
@@ -124,7 +124,6 @@
obj = module.fooType.classmeth()
assert obj is module.fooType
- @pytest.mark.skipif('__pypy__' not in sys.builtin_module_names, reason='cpython segfaults')
def test_new(self):
# XXX cpython segfaults but if run singly (with -k test_new) this passes
module = self.import_module(name='foo')
@@ -179,8 +178,6 @@
x = module.MetaType('name', (), {})
assert isinstance(x, type)
assert isinstance(x, module.MetaType)
- if self.runappdirect and '__pypy__' in sys.builtin_module_names:
- skip('x is not callable when runappdirect??')
x()
def test_metaclass_compatible(self):
@@ -190,13 +187,11 @@
assert type(module.fooType).__mro__ == (type, object)
y = module.MetaType('other', (module.MetaType,), {})
assert isinstance(y, module.MetaType)
- if self.runappdirect and '__pypy__' in sys.builtin_module_names:
- skip('y is not callable when runappdirect??')
x = y('something', (type(y),), {})
del x, y
def test_metaclass_compatible2(self):
- skip('type.__new__ does not check acceptable_as_base_class')
+ skip('fails even with -A, fooType has BASETYPE flag')
# XXX FIX - must raise since fooType (which is a base type)
# does not have flag Py_TPFLAGS_BASETYPE
module = self.import_module(name='foo')
@@ -880,7 +875,6 @@
#print('calling module.footype()...')
module.footype("X", (object,), {})
- @pytest.mark.skipif('__pypy__' not in sys.builtin_module_names, reason='cpython fails')
def test_app_subclass_of_c_type(self):
# on cpython, the size changes (6 bytes added)
module = self.import_module(name='foo')
diff --git a/pypy/module/cpyext/unicodeobject.py b/pypy/module/cpyext/unicodeobject.py
--- a/pypy/module/cpyext/unicodeobject.py
+++ b/pypy/module/cpyext/unicodeobject.py
@@ -792,7 +792,7 @@
@cpython_api([PyObject, PyObject], PyObject)
def PyUnicode_Concat(space, w_left, w_right):
"""Concat two strings giving a new Unicode string."""
- return space.call_method(w_left, '__add__', w_right)
+ return space.add(w_left, w_right)
@cpython_api([PyObject, CONST_STRING], rffi.INT_real, error=CANNOT_FAIL)
def PyUnicode_CompareWithASCIIString(space, w_uni, string):
diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py
--- a/pypy/objspace/std/bytearrayobject.py
+++ b/pypy/objspace/std/bytearrayobject.py
@@ -5,6 +5,9 @@
from rpython.rlib.buffer import Buffer
from rpython.rlib.rstring import StringBuilder, ByteListBuilder
from rpython.rlib.debug import check_list_of_chars
+from rpython.rtyper.lltypesystem import rffi
+from rpython.rlib.rgc import (resizable_list_supporting_raw_ptr,
+ nonmoving_raw_ptr_for_resizable_list)
from pypy.interpreter.baseobjspace import W_Root
from pypy.interpreter.error import OperationError, oefmt
@@ -25,7 +28,7 @@
def __init__(self, data):
check_list_of_chars(data)
- self.data = data
+ self.data = resizable_list_supporting_raw_ptr(data)
def __repr__(self):
"""representation for debugging purposes"""
@@ -34,6 +37,12 @@
def buffer_w(self, space, flags):
return BytearrayBuffer(self.data, False)
+ def bytearray_list_of_chars_w(self, space):
+ return self.data
+
+ def nonmovable_carray(self, space):
+ return BytearrayBuffer(self.data, False).get_raw_address()
+
def _new(self, value):
if value is self.data:
value = value[:]
@@ -176,7 +185,8 @@
@unwrap_spec(encoding='str_or_None', errors='str_or_None')
def descr_init(self, space, w_source=None, encoding=None, errors=None):
assert isinstance(self, W_BytearrayObject)
- self.data = newbytesdata_w(space, w_source, encoding, errors)
+ data = newbytesdata_w(space, w_source, encoding, errors)
+ self.data = resizable_list_supporting_raw_ptr(data)
def descr_repr(self, space):
s = self.data
@@ -457,6 +467,8 @@
return val - 87
return -1
+NON_HEX_MSG = "non-hexadecimal number found in fromhex() arg at position %d"
+
def _hexstring_to_array(space, s):
data = []
length = len(s)
@@ -467,21 +479,15 @@
if i >= length:
break
if i + 1 == length:
- raise oefmt(space.w_ValueError,
- "non-hexadecimal number found in fromhex() arg at "
- "position %d", i)
+ raise oefmt(space.w_ValueError, NON_HEX_MSG, i)
top = _hex_digit_to_int(s[i])
if top == -1:
- raise oefmt(space.w_ValueError,
- "non-hexadecimal number found in fromhex() arg at "
- "position %d", i)
- bot = _hex_digit_to_int(s[i+1])
+ raise oefmt(space.w_ValueError, NON_HEX_MSG, i)
+ bot = _hex_digit_to_int(s[i + 1])
if bot == -1:
- raise oefmt(space.w_ValueError,
- "non-hexadecimal number found in fromhex() arg at "
- "position %d", i + 1)
- data.append(chr(top*16 + bot))
+ raise oefmt(space.w_ValueError, NON_HEX_MSG, i + 1)
+ data.append(chr(top * 16 + bot))
i += 2
return data
@@ -1184,6 +1190,9 @@
for i in range(len(string)):
self.data[start + i] = string[i]
+ def get_raw_address(self):
+ return nonmoving_raw_ptr_for_resizable_list(self.data)
+
@specialize.argtype(1)
def _memcmp(selfvalue, buffer, length):
diff --git a/pypy/objspace/std/test/test_memoryobject.py b/pypy/objspace/std/test/test_memoryobject.py
--- a/pypy/objspace/std/test/test_memoryobject.py
+++ b/pypy/objspace/std/test/test_memoryobject.py
@@ -159,5 +159,5 @@
def test_pypy_raw_address_base(self):
raises(ValueError, memoryview(b"foobar")._pypy_raw_address)
- e = raises(ValueError, memoryview(bytearray(b"foobar"))._pypy_raw_address)
- assert 'BytearrayBuffer' in str(e.value)
+ a = memoryview(bytearray(b"foobar"))._pypy_raw_address()
+ assert a != 0
More information about the pypy-commit
mailing list