Author: Matti Picus <[email protected]>
Branch:
Changeset: r95100:0fe67a6981d9
Date: 2018-09-11 23:35 +0300
http://bitbucket.org/pypy/pypy/changeset/0fe67a6981d9/
Log: Backed out changeset: 943b0266d564
diff too long, truncating to 2000 out of 24114 lines
diff --git a/pypy/module/cpyext/test/test_abstract.py
b/pypy/module/cpyext/test/test_abstract.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/test/test_abstract.py
@@ -0,0 +1,130 @@
+from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
+import pytest
+
+class AppTestBufferProtocol(AppTestCpythonExtensionBase):
+ """Tests for the old buffer protocol."""
+
+ def w_get_buffer_support(self):
+ return self.import_extension('buffer_support', [
+ ("charbuffer_as_string", "METH_O",
+ """
+ char *ptr;
+ Py_ssize_t size;
+ if (PyObject_AsCharBuffer(args, (const char **)&ptr, &size) <
0)
+ return NULL;
+ return PyString_FromStringAndSize(ptr, size);
+ """),
+ ("check_readbuffer", "METH_O",
+ """
+ return PyBool_FromLong(PyObject_CheckReadBuffer(args));
+ """),
+ ("readbuffer_as_string", "METH_O",
+ """
+ const void *ptr;
+ Py_ssize_t size;
+ if (PyObject_AsReadBuffer(args, &ptr, &size) < 0)
+ return NULL;
+ return PyString_FromStringAndSize((char*)ptr, size);
+ """),
+ ("writebuffer_as_string", "METH_O",
+ """
+ void *ptr;
+ Py_ssize_t size;
+ if (PyObject_AsWriteBuffer(args, &ptr, &size) < 0)
+ return NULL;
+ return PyString_FromStringAndSize((char*)ptr, size);
+ """),
+ ("zero_out_writebuffer", "METH_O",
+ """
+ void *ptr;
+ Py_ssize_t size;
+ Py_ssize_t i;
+ if (PyObject_AsWriteBuffer(args, &ptr, &size) < 0)
+ return NULL;
+ for (i = 0; i < size; i++) {
+ ((char*)ptr)[i] = 0;
+ }
+ Py_RETURN_NONE;
+ """),
+ ])
+
+ def test_string(self):
+ buffer_support = self.get_buffer_support()
+
+ s = 'a\0x'
+
+ assert buffer_support.check_readbuffer(s)
+ assert s == buffer_support.readbuffer_as_string(s)
+ assert raises(TypeError, buffer_support.writebuffer_as_string, s)
+ assert s == buffer_support.charbuffer_as_string(s)
+
+ def test_buffer(self):
+ buffer_support = self.get_buffer_support()
+
+ s = 'a\0x'
+ buf = buffer(s)
+
+ assert buffer_support.check_readbuffer(buf)
+ assert s == buffer_support.readbuffer_as_string(buf)
+ assert raises(TypeError, buffer_support.writebuffer_as_string, buf)
+ assert s == buffer_support.charbuffer_as_string(buf)
+
+ def test_mmap(self):
+ import mmap
+ buffer_support = self.get_buffer_support()
+
+ s = 'a\0x'
+ mm = mmap.mmap(-1, 3)
+ mm[:] = s
+
+ assert buffer_support.check_readbuffer(mm)
+ assert s == buffer_support.readbuffer_as_string(mm)
+ assert s == buffer_support.writebuffer_as_string(mm)
+ assert s == buffer_support.charbuffer_as_string(mm)
+
+ s = '\0' * 3
+ buffer_support.zero_out_writebuffer(mm)
+ assert s == ''.join(mm)
+ assert s == buffer_support.readbuffer_as_string(mm)
+ assert s == buffer_support.writebuffer_as_string(mm)
+ assert s == buffer_support.charbuffer_as_string(mm)
+
+ s = '\0' * 3
+ ro_mm = mmap.mmap(-1, 3, access=mmap.ACCESS_READ)
+ assert buffer_support.check_readbuffer(ro_mm)
+ assert s == buffer_support.readbuffer_as_string(ro_mm)
+ assert raises(TypeError, buffer_support.writebuffer_as_string, ro_mm)
+ assert s == buffer_support.charbuffer_as_string(ro_mm)
+
+ def test_array(self):
+ import array
+ buffer_support = self.get_buffer_support()
+
+ s = 'a\0x'
+ a = array.array('B', [5, 0, 10])
+
+ buffer_support.zero_out_writebuffer(a)
+ assert list(a) == [0, 0, 0]
+
+ def test_nonbuffer(self):
+ # e.g. int
+ buffer_support = self.get_buffer_support()
+
+ assert not buffer_support.check_readbuffer(42)
+ assert raises(TypeError, buffer_support.readbuffer_as_string, 42)
+ assert raises(TypeError, buffer_support.writebuffer_as_string, 42)
+ assert raises(TypeError, buffer_support.charbuffer_as_string, 42)
+
+ def test_user_class(self):
+ class MyBuf(str):
+ pass
+ s = 'a\0x'
+ buf = MyBuf(s)
+ buffer_support = self.get_buffer_support()
+
+ assert buffer_support.check_readbuffer(buf)
+ assert s == buffer_support.readbuffer_as_string(buf)
+ assert raises(TypeError, buffer_support.writebuffer_as_string, buf)
+ assert s == buffer_support.charbuffer_as_string(buf)
+
+
diff --git a/pypy/module/cpyext/test/test_arraymodule.py
b/pypy/module/cpyext/test/test_arraymodule.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/test/test_arraymodule.py
@@ -0,0 +1,197 @@
+import pytest
+from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
+from pypy.conftest import option
+
+class AppTestArrayModule(AppTestCpythonExtensionBase):
+ enable_leak_checking = True
+
+ def setup_class(cls):
+ from rpython.tool.udir import udir
+ AppTestCpythonExtensionBase.setup_class.im_func(cls)
+ if option.runappdirect:
+ cls.w_udir = str(udir)
+ else:
+ cls.w_udir = cls.space.wrap(str(udir))
+
+
+ def test_basic(self):
+ module = self.import_module(name='array')
+ arr = module.array('i', [1,2,3])
+ assert arr.typecode == 'i'
+ assert arr.itemsize == 4
+ assert arr[2] == 3
+ assert len(arr.buffer_info()) == 2
+ exc = raises(TypeError, module.array.append)
+ errstr = str(exc.value)
+ assert errstr.startswith("descriptor 'append' of")
+ arr.append(4)
+ assert arr.tolist() == [1, 2, 3, 4]
+ assert len(arr) == 4
+
+ def test_iter(self):
+ module = self.import_module(name='array')
+ arr = module.array('i', [1,2,3])
+ sum = 0
+ for i in arr:
+ sum += i
+ assert sum == 6
+
+ def test_index(self):
+ module = self.import_module(name='array')
+ arr = module.array('i', [1, 2, 3, 4])
+ assert arr[3] == 4
+ raises(IndexError, arr.__getitem__, 10)
+ del arr[2]
+ assert arr.tolist() == [1, 2, 4]
+ arr[2] = 99
+ assert arr.tolist() == [1, 2, 99]
+
+ def test_slice_get(self):
+ module = self.import_module(name='array')
+ arr = module.array('i', [1, 2, 3, 4])
+ assert arr[:].tolist() == [1, 2, 3, 4]
+ assert arr[1:].tolist() == [2, 3, 4]
+ assert arr[:2].tolist() == [1, 2]
+ assert arr[1:3].tolist() == [2, 3]
+
+ def test_slice_object(self):
+ module = self.import_module(name='array')
+ arr = module.array('i', [1, 2, 3, 4])
+ assert arr[slice(1, 3)].tolist() == [2,3]
+ arr[slice(1, 3)] = module.array('i', [21, 22, 23])
+ assert arr.tolist() == [1, 21, 22, 23, 4]
+ del arr[slice(1, 3)]
+ assert arr.tolist() == [1, 23, 4]
+ raises(TypeError, 'arr[slice(1, 3)] = "abc"')
+
+ def test_buffer(self):
+ import sys
+ module = self.import_module(name='array')
+ arr = module.array('i', [1, 2, 3, 4])
+ buf = buffer(arr)
+ exc = raises(TypeError, "buf[1] = '1'")
+ assert str(exc.value) == "buffer is read-only"
+ if sys.byteorder == 'big':
+ expected = '\0\0\0\x01' '\0\0\0\x02' '\0\0\0\x03' '\0\0\0\x04'
+ else:
+ expected = '\x01\0\0\0' '\x02\0\0\0' '\x03\0\0\0' '\x04\0\0\0'
+ assert str(buf) == expected
+ assert str(buffer('a') + arr) == "a" + expected
+ # python2 special cases empty-buffer + obj
+ assert str(buffer('') + arr) == "array('i', [1, 2, 3, 4])"
+
+ def test_releasebuffer(self):
+ module = self.import_module(name='array')
+ arr = module.array('i', [1,2,3,4])
+ assert module.get_releasebuffer_cnt() == 0
+ module.create_and_release_buffer(arr)
+ assert module.get_releasebuffer_cnt() == 1
+
+ def test_Py_buffer(self):
+ module = self.import_module(name='array')
+ arr = module.array('i', [1,2,3,4])
+ assert module.get_releasebuffer_cnt() == 0
+ m = memoryview(arr)
+ assert module.get_releasebuffer_cnt() == 0
+ del m
+ self.debug_collect()
+ assert module.get_releasebuffer_cnt() == 1
+
+ def test_pickle(self):
+ import pickle
+ module = self.import_module(name='array')
+ arr = module.array('i', [1,2,3,4])
+ s = pickle.dumps(arr)
+ # pypy exports __dict__ on cpyext objects, so the pickle picks up the
{} state value
+ #assert s ==
"carray\n_reconstruct\np0\n(S'i'\np1\n(lp2\nI1\naI2\naI3\naI4\natp3\nRp4\n."
+ rra = pickle.loads(s) # rra is arr backwards
+ #assert arr.tolist() == rra.tolist()
+
+ def test_binop_mul_impl(self):
+ # check that rmul is called
+ module = self.import_module(name='array')
+ arr = module.array('i', [2])
+ res = [1, 2, 3] * arr
+ assert res == [1, 2, 3, 1, 2, 3]
+ module.switch_multiply()
+ res = [1, 2, 3] * arr
+ assert res == [2, 4, 6]
+
+ @pytest.mark.xfail
+ def test_subclass_dealloc(self):
+ module = self.import_module(name='array')
+ class Sub(module.array):
+ pass
+
+ arr = Sub('i', [2])
+ module.readbuffer_as_string(arr)
+ class A(object):
+ pass
+ assert not module.same_dealloc(arr, module.array('i', [2]))
+ assert module.same_dealloc(arr, A())
+
+ def test_subclass(self):
+ import struct
+ module = self.import_module(name='array')
+ class Sub(module.array):
+ pass
+
+ arr = Sub('i', [2])
+ res = [1, 2, 3] * arr
+ assert res == [1, 2, 3, 1, 2, 3]
+
+ val = module.readbuffer_as_string(arr)
+ assert val == struct.pack('i', 2)
+
+ def test_unicode_readbuffer(self):
+ # Not really part of array, refactor
+ import struct
+ module = self.import_module(name='array')
+ val = module.readbuffer_as_string('abcd')
+ assert val == 'abcd'
+ val = module.readbuffer_as_string(u'\u03a3')
+ assert val is not None
+
+ def test_readinto(self):
+ module = self.import_module(name='array')
+ a = module.array('c')
+ a.fromstring('0123456789')
+ filename = self.udir + "/_test_file"
+ f = open(filename, 'w+b')
+ f.write('foobar')
+ f.seek(0)
+ n = f.readinto(a)
+ f.close()
+ assert n == 6
+ assert len(a) == 10
+ assert a.tostring() == 'foobar6789'
+
+ def test_iowrite(self):
+ module = self.import_module(name='array')
+ from io import BytesIO
+ a = module.array('c')
+ a.fromstring('0123456789')
+ fd = BytesIO()
+ # only test that it works
+ fd.write(a)
+
+ def test_getitem_via_PySequence_GetItem(self):
+ module = self.import_module(name='array')
+ a = module.array('i', range(10))
+ # call via tp_as_mapping.mp_subscript
+ assert 5 == a[-5]
+ # PySequence_ITEM used to call space.getitem() which
+ # prefers tp_as_mapping.mp_subscript over tp_as_sequence.sq_item
+ # Now fixed so this test raises (array_item does not add len(a),
+ # array_subscr does)
+ raises(IndexError, module.getitem, a, -5)
+
+ def test_subclass_with_attribute(self):
+ module = self.import_module(name='array')
+ class Sub(module.array):
+ def addattrib(self):
+ print('called addattrib')
+ self.attrib = True
+ import gc
+ module.subclass_with_attribute(Sub, "addattrib", "attrib", gc.collect)
+ assert Sub.__module__ == __name__
diff --git a/pypy/module/cpyext/test/test_boolobject.py
b/pypy/module/cpyext/test/test_boolobject.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/test/test_boolobject.py
@@ -0,0 +1,48 @@
+from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
+from pypy.module.cpyext.test.test_api import BaseApiTest
+from pypy.module.cpyext.boolobject import PyBool_FromLong
+
+class TestBoolObject(BaseApiTest):
+ def test_fromlong(self, space):
+ for i in range(-3, 3):
+ obj = PyBool_FromLong(space, i)
+ if i:
+ assert obj is space.w_True
+ else:
+ assert obj is space.w_False
+
+class AppTestBoolMacros(AppTestCpythonExtensionBase):
+ def test_macros(self):
+ module = self.import_extension('foo', [
+ ("get_true", "METH_NOARGS", "Py_RETURN_TRUE;"),
+ ("get_false", "METH_NOARGS", "Py_RETURN_FALSE;"),
+ ])
+ assert module.get_true() == True
+ assert module.get_false() == False
+
+ def test_toint(self):
+ module = self.import_extension('foo', [
+ ("to_int", "METH_O",
+ '''
+ if (args->ob_type->tp_as_number &&
args->ob_type->tp_as_number->nb_int) {
+ return args->ob_type->tp_as_number->nb_int(args);
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError,"cannot convert bool to
int");
+ return NULL;
+ }
+ '''), ])
+ assert module.to_int(False) == 0
+ assert module.to_int(True) == 1
+
+ def test_check(self):
+ module = self.import_extension('foo', [
+ ("type_check", "METH_O",
+ '''
+ return PyLong_FromLong(PyBool_Check(args));
+ ''')])
+ assert module.type_check(True)
+ assert module.type_check(False)
+ assert not module.type_check(None)
+ assert not module.type_check(1.0)
+
diff --git a/pypy/module/cpyext/test/test_borrow.py
b/pypy/module/cpyext/test/test_borrow.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/test/test_borrow.py
@@ -0,0 +1,71 @@
+import py
+from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
+from pypy.module.cpyext.test.test_api import BaseApiTest
+from pypy.module.cpyext.pyobject import make_ref
+
+
+class AppTestBorrow(AppTestCpythonExtensionBase):
+ def test_tuple_borrowing(self):
+ module = self.import_extension('foo', [
+ ("test_borrowing", "METH_NOARGS",
+ """
+ PyObject *t = PyTuple_New(1);
+ PyObject *f = PyFloat_FromDouble(42.0);
+ PyObject *g = NULL;
+ printf("Refcnt1: %ld\\n", f->ob_refcnt);
+ PyTuple_SetItem(t, 0, f); // steals reference
+ printf("Refcnt2: %ld\\n", f->ob_refcnt);
+ f = PyTuple_GetItem(t, 0); // borrows reference
+ printf("Refcnt3: %ld\\n", f->ob_refcnt);
+ g = PyTuple_GetItem(t, 0); // borrows reference again
+ printf("Refcnt4: %ld\\n", f->ob_refcnt);
+ printf("COMPARE: %i\\n", f == g);
+ fflush(stdout);
+ Py_DECREF(t);
+ Py_RETURN_TRUE;
+ """),
+ ])
+ assert module.test_borrowing() # the test should not leak
+
+ def test_borrow_destroy(self):
+ module = self.import_extension('foo', [
+ ("test_borrow_destroy", "METH_NOARGS",
+ """
+ PyObject *i = PyInt_FromLong(42);
+ PyObject *j;
+ PyObject *t1 = PyTuple_Pack(1, i);
+ PyObject *t2 = PyTuple_Pack(1, i);
+ Py_DECREF(i);
+
+ i = PyTuple_GetItem(t1, 0);
+ PyTuple_GetItem(t2, 0);
+ Py_DECREF(t2);
+
+ j = PyInt_FromLong(PyInt_AsLong(i));
+ Py_DECREF(t1);
+ return j;
+ """),
+ ])
+ assert module.test_borrow_destroy() == 42
+
+ def test_double_borrow(self):
+ if self.runappdirect:
+ py.test.xfail('segfault')
+ module = self.import_extension('foo', [
+ ("run", "METH_NOARGS",
+ """
+ PyObject *t = PyTuple_New(1);
+ PyObject *s = PyRun_String("set()", Py_eval_input,
+ Py_None, Py_None);
+ PyObject *w = PyWeakref_NewRef(s, Py_None);
+ PyTuple_SetItem(t, 0, s);
+ PyTuple_GetItem(t, 0);
+ PyTuple_GetItem(t, 0);
+ Py_DECREF(t);
+ return w;
+ """),
+ ])
+ wr = module.run()
+ # check that the set() object was deallocated
+ self.debug_collect()
+ assert wr() is None
diff --git a/pypy/module/cpyext/test/test_bufferobject.py
b/pypy/module/cpyext/test/test_bufferobject.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/test/test_bufferobject.py
@@ -0,0 +1,123 @@
+from rpython.rtyper.lltypesystem import lltype
+from pypy.module.cpyext.test.test_api import BaseApiTest
+from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
+from pypy.module.cpyext.api import PyObject
+
+class AppTestBufferObject(AppTestCpythonExtensionBase):
+
+ def test_FromMemory(self):
+ module = self.import_extension('foo', [
+ ("get_FromMemory", "METH_NOARGS",
+ """
+ cbuf = malloc(4);
+ cbuf[0] = 'a';
+ cbuf[1] = 'b';
+ cbuf[2] = 'c';
+ cbuf[3] = '\\0';
+ return PyBuffer_FromMemory(cbuf, 4);
+ """),
+ ("free_buffer", "METH_NOARGS",
+ """
+ free(cbuf);
+ Py_RETURN_NONE;
+ """),
+ ("check_ascharbuffer", "METH_O",
+ """
+ char *ptr;
+ Py_ssize_t size;
+ if (PyObject_AsCharBuffer(args, (const char **)&ptr, &size) <
0)
+ return NULL;
+ return PyString_FromStringAndSize(ptr, size);
+ """)
+ ], prologue = """
+ static char* cbuf = NULL;
+ """)
+ buf = module.get_FromMemory()
+ assert str(buf) == 'abc\0'
+
+ assert module.check_ascharbuffer(buf) == 'abc\0'
+
+ module.free_buffer()
+
+ def test_Buffer_New(self):
+ module = self.import_extension('foo', [
+ ("buffer_new", "METH_NOARGS",
+ """
+ return PyBuffer_New(150);
+ """),
+ ])
+ b = module.buffer_new()
+ raises(AttributeError, getattr, b, 'x')
+
+ def test_array_buffer(self):
+ if self.runappdirect:
+ skip('PyBufferObject not available outside buffer object.c')
+ module = self.import_extension('foo', [
+ ("roundtrip", "METH_O",
+ """
+ PyBufferObject *buf = (PyBufferObject *)args;
+ return PyString_FromStringAndSize(buf->b_ptr, buf->b_size);
+ """),
+ ])
+ import array
+ a = array.array('c', 'text')
+ b = buffer(a)
+ assert module.roundtrip(b) == 'text'
+
+
+ def test_issue2752(self):
+ iterations = 10
+ if self.runappdirect:
+ iterations = 2000
+ module = self.import_extension('foo', [
+ ("test_mod", 'METH_VARARGS',
+ """
+ PyObject *obj;
+ Py_buffer bp;
+ if (!PyArg_ParseTuple(args, "O", &obj))
+ return NULL;
+
+ if (PyObject_GetBuffer(obj, &bp, PyBUF_SIMPLE) == -1)
+ return NULL;
+
+ if (((unsigned char*)bp.buf)[0] != '0') {
+ void * buf = (void*)bp.buf;
+ unsigned char val[4];
+ char * s = PyString_AsString(obj);
+ memcpy(val, bp.buf, 4);
+ PyBuffer_Release(&bp);
+ if (PyObject_GetBuffer(obj, &bp, PyBUF_SIMPLE) == -1)
+ return NULL;
+ PyErr_Format(PyExc_ValueError,
+ "mismatch: %p [%x %x %x %x...] now %p [%x %x %x
%x...] as str '%s'",
+ buf, val[0], val[1], val[2], val[3],
+ (void *)bp.buf,
+ ((unsigned char*)bp.buf)[0],
+ ((unsigned char*)bp.buf)[1],
+ ((unsigned char*)bp.buf)[2],
+ ((unsigned char*)bp.buf)[3],
+ s);
+ PyBuffer_Release(&bp);
+ return NULL;
+ }
+
+ PyBuffer_Release(&bp);
+ Py_RETURN_NONE;
+ """),
+ ])
+ bufsize = 4096
+ def getdata(bufsize):
+ data = b'01234567'
+ for x in range(18):
+ data += data
+ if len(data) >= bufsize:
+ break
+ return data
+ for j in range(iterations):
+ block = getdata(bufsize)
+ assert block[:8] == '01234567'
+ try:
+ module.test_mod(block)
+ except ValueError as e:
+ print("%s at it=%d" % (e, j))
+ assert False
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,188 @@
+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;
+
+ if(PyByteArray_Size(s) == 12) {
+ result = 1;
+ }
+ 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;
+
+ 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;
+ 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",
+ """
+ const char *c;
+ PyObject *s2, *s1 = PyByteArray_FromStringAndSize("test", 4);
+ if (s1 == NULL)
+ return NULL;
+ c = PyByteArray_AsString(s1);
+ s2 = PyByteArray_FromStringAndSize(c, 4);
+ Py_DECREF(s1);
+ return s2;
+ """),
+ ])
+ s = module.getbytearray()
+ assert s == b'test'
+
+ def test_manipulations(self):
+ import sys
+ 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'
+ if '__pypy__' in sys.builtin_module_names:
+ # CPython only makes an assert.
+ 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_bytesobject.py
b/pypy/module/cpyext/test/test_bytesobject.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/test/test_bytesobject.py
@@ -0,0 +1,611 @@
+# encoding: utf-8
+import pytest
+from rpython.rtyper.lltypesystem import rffi, lltype
+from pypy.interpreter.error import OperationError
+from pypy.module.cpyext.test.test_api import BaseApiTest, raises_w
+from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
+from pypy.module.cpyext.bytesobject import (
+ new_empty_str, PyBytesObject, _PyString_Resize, PyString_Concat,
+ PyString_ConcatAndDel, PyString_Format, PyString_InternFromString,
+ PyString_AsEncodedObject, PyString_AsDecodedObject, _PyString_Eq,
+ _PyString_Join)
+from pypy.module.cpyext.api import PyObjectP, PyObject, Py_ssize_tP,
generic_cpy_call
+from pypy.module.cpyext.pyobject import decref, from_ref, make_ref
+from pypy.module.cpyext.buffer import PyObject_AsCharBuffer
+from pypy.module.cpyext.api import PyTypeObjectPtr
+
+
+class AppTestBytesObject(AppTestCpythonExtensionBase):
+ def test_bytesobject(self):
+ module = self.import_extension('foo', [
+ ("get_hello1", "METH_NOARGS",
+ """
+ return PyBytes_FromStringAndSize(
+ "Hello world<should not be included>", 11);
+ """),
+ ("get_hello2", "METH_NOARGS",
+ """
+ return PyBytes_FromString("Hello world");
+ """),
+ ("test_Size", "METH_NOARGS",
+ """
+ PyObject* s = PyBytes_FromString("Hello world");
+ int result = PyBytes_Size(s);
+
+ Py_DECREF(s);
+ return PyLong_FromLong(result);
+ """),
+ ("test_Size_exception", "METH_NOARGS",
+ """
+ PyObject* f = PyFloat_FromDouble(1.0);
+ PyBytes_Size(f);
+
+ Py_DECREF(f);
+ return NULL;
+ """),
+ ("test_is_bytes", "METH_VARARGS",
+ """
+ return PyBool_FromLong(PyBytes_Check(PyTuple_GetItem(args,
0)));
+ """)], prologue='#include <stdlib.h>')
+ assert module.get_hello1() == b'Hello world'
+ assert module.get_hello2() == b'Hello world'
+ assert module.test_Size() == 11
+ raises(TypeError, module.test_Size_exception)
+
+ assert module.test_is_bytes(b"")
+ assert not module.test_is_bytes(())
+
+ def test_bytes_buffer_init(self):
+ module = self.import_extension('foo', [
+ ("getbytes", "METH_NOARGS",
+ """
+ PyObject *s, *t;
+ char* c;
+
+ s = PyBytes_FromStringAndSize(NULL, 4);
+ if (s == NULL)
+ return NULL;
+ t = PyBytes_FromStringAndSize(NULL, 3);
+ if (t == NULL)
+ return NULL;
+ Py_DECREF(t);
+ c = PyBytes_AS_STRING(s);
+ c[0] = 'a';
+ c[1] = 'b';
+ c[2] = 0;
+ c[3] = 'c';
+ return s;
+ """),
+ ])
+ s = module.getbytes()
+ assert len(s) == 4
+ assert s == b'ab\x00c'
+
+ def test_bytes_tp_alloc(self):
+ module = self.import_extension('foo', [
+ ("tpalloc", "METH_NOARGS",
+ """
+ PyObject *base;
+ PyTypeObject * type;
+ PyBytesObject *obj;
+ base = PyBytes_FromString("test");
+ if (PyBytes_GET_SIZE(base) != 4)
+ return PyLong_FromLong(-PyBytes_GET_SIZE(base));
+ type = base->ob_type;
+ if (type->tp_itemsize != 1)
+ return PyLong_FromLong(type->tp_itemsize);
+ obj = (PyBytesObject*)type->tp_alloc(type, 10);
+ if (PyBytes_GET_SIZE(obj) != 10)
+ return PyLong_FromLong(PyBytes_GET_SIZE(obj));
+ /* cannot work, there is only RO access
+ memcpy(PyBytes_AS_STRING(obj), "works", 6); */
+ Py_INCREF(obj);
+ return (PyObject*)obj;
+ """),
+ ('alloc_rw', "METH_NOARGS",
+ '''
+ PyObject *obj = (PyObject*)_PyObject_NewVar(&PyBytes_Type, 10);
+ memcpy(PyBytes_AS_STRING(obj), "works", 6);
+ return (PyObject*)obj;
+ '''),
+ ])
+ s = module.alloc_rw()
+ assert s[:6] == b'works\0' # s[6:10] contains random garbage
+ s = module.tpalloc()
+ assert s == b'\x00' * 10
+
+ def test_AsString(self):
+ module = self.import_extension('foo', [
+ ("getbytes", "METH_NOARGS",
+ """
+ char *c;
+ PyObject* s2, *s1 = PyBytes_FromStringAndSize("test", 4);
+ c = PyBytes_AsString(s1);
+ s2 = PyBytes_FromStringAndSize(c, 4);
+ Py_DECREF(s1);
+ return s2;
+ """),
+ ])
+ s = module.getbytes()
+ assert s == b'test'
+
+ def test_manipulations(self):
+ module = self.import_extension('foo', [
+ ("bytes_as_string", "METH_VARARGS",
+ '''
+ return PyBytes_FromStringAndSize(PyBytes_AsString(
+ PyTuple_GetItem(args, 0)), 4);
+ '''
+ ),
+ ("concat", "METH_VARARGS",
+ """
+ PyObject ** v;
+ PyObject * left = PyTuple_GetItem(args, 0);
+ Py_INCREF(left); /* the reference will be stolen! */
+ v = &left;
+ PyBytes_Concat(v, PyTuple_GetItem(args, 1));
+ return *v;
+ """)])
+ assert module.bytes_as_string(b"huheduwe") == b"huhe"
+ ret = module.concat(b'abc', b'def')
+ assert ret == b'abcdef'
+ ret = module.concat('abc', u'def')
+ assert not isinstance(ret, str)
+ assert isinstance(ret, unicode)
+ assert ret == 'abcdef'
+
+ def test_py_bytes_as_string_None(self):
+ module = self.import_extension('foo', [
+ ("string_None", "METH_VARARGS",
+ '''
+ if (PyBytes_AsString(Py_None)) {
+ Py_RETURN_NONE;
+ }
+ return NULL;
+ '''
+ )])
+ raises(TypeError, module.string_None)
+
+ def test_AsStringAndSize(self):
+ module = self.import_extension('foo', [
+ ("getbytes", "METH_NOARGS",
+ """
+ PyObject* s1 = PyBytes_FromStringAndSize("te\\0st", 5);
+ char *buf;
+ Py_ssize_t len;
+ if (PyBytes_AsStringAndSize(s1, &buf, &len) < 0)
+ return NULL;
+ if (len != 5) {
+ PyErr_SetString(PyExc_AssertionError, "Bad Length");
+ return NULL;
+ }
+ if (PyBytes_AsStringAndSize(s1, &buf, NULL) >= 0) {
+ PyErr_SetString(PyExc_AssertionError, "Should Have
failed");
+ return NULL;
+ }
+ PyErr_Clear();
+ Py_DECREF(s1);
+ 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()
+
+ def test_py_string_as_string_Unicode(self):
+ module = self.import_extension('foo', [
+ ("getstring_unicode", "METH_NOARGS",
+ """
+ Py_UNICODE chars[] = {'t', 'e', 's', 't'};
+ PyObject* u1 = PyUnicode_FromUnicode(chars, 4);
+ char *buf;
+ buf = PyString_AsString(u1);
+ if (buf == NULL)
+ return NULL;
+ if (buf[3] != 't') {
+ PyErr_SetString(PyExc_AssertionError, "Bad conversion");
+ return NULL;
+ }
+ Py_DECREF(u1);
+ Py_INCREF(Py_None);
+ return Py_None;
+ """),
+ ("getstringandsize_unicode", "METH_NOARGS",
+ """
+ Py_UNICODE chars[] = {'t', 'e', 's', 't'};
+ PyObject* u1 = PyUnicode_FromUnicode(chars, 4);
+ char *buf;
+ Py_ssize_t len;
+ if (PyString_AsStringAndSize(u1, &buf, &len) < 0)
+ return NULL;
+ if (len != 4) {
+ PyErr_SetString(PyExc_AssertionError, "Bad Length");
+ return NULL;
+ }
+ Py_DECREF(u1);
+ Py_INCREF(Py_None);
+ return Py_None;
+ """),
+ ])
+ module.getstring_unicode()
+ module.getstringandsize_unicode()
+
+ def test_format_v(self):
+ module = self.import_extension('foo', [
+ ("test_string_format_v", "METH_VARARGS",
+ '''
+ return helper("bla %d ble %s\\n",
+ PyInt_AsLong(PyTuple_GetItem(args, 0)),
+ PyString_AsString(PyTuple_GetItem(args, 1)));
+ '''
+ )
+ ], prologue='''
+ PyObject* helper(char* fmt, ...)
+ {
+ va_list va;
+ PyObject* res;
+ va_start(va, fmt);
+ res = PyString_FromFormatV(fmt, va);
+ va_end(va);
+ return res;
+ }
+ ''')
+ res = module.test_string_format_v(1, "xyz")
+ assert res == "bla 1 ble xyz\n"
+
+ def test_format(self):
+ module = self.import_extension('foo', [
+ ("test_string_format", "METH_VARARGS",
+ '''
+ return PyString_FromFormat("bla %d ble %s\\n",
+ PyInt_AsLong(PyTuple_GetItem(args, 0)),
+ PyString_AsString(PyTuple_GetItem(args, 1)));
+ '''
+ )
+ ])
+ res = module.test_string_format(1, "xyz")
+ assert res == "bla 1 ble xyz\n"
+
+ def test_intern_inplace(self):
+ module = self.import_extension('foo', [
+ ("test_intern_inplace", "METH_O",
+ '''
+ PyObject *s = args;
+ Py_INCREF(s);
+ PyString_InternInPlace(&s);
+ if (((PyBytesObject*)s)->ob_sstate == SSTATE_NOT_INTERNED)
+ {
+ Py_DECREF(s);
+ s = PyString_FromString("interned error");
+ }
+ return s;
+ '''
+ )
+ ])
+ # This does not test much, but at least the refcounts are checked.
+ assert module.test_intern_inplace('s') == 's'
+
+ def test_bytes_macros(self):
+ """The PyString_* macros cast, and calls expecting that build."""
+ module = self.import_extension('foo', [
+ ("test_macro_invocations", "METH_NOARGS",
+ """
+ PyObject* o = PyString_FromString("");
+ PyBytesObject* u = (PyBytesObject*)o;
+
+ PyString_GET_SIZE(u);
+ PyString_GET_SIZE(o);
+
+ PyString_AS_STRING(o);
+ PyString_AS_STRING(u);
+
+ return o;
+ """)])
+ assert module.test_macro_invocations() == ''
+
+ def test_hash_and_state(self):
+ module = self.import_extension('foo', [
+ ("test_hash", "METH_VARARGS",
+ '''
+ PyObject* obj = (PyTuple_GetItem(args, 0));
+ long hash = ((PyBytesObject*)obj)->ob_shash;
+ return PyLong_FromLong(hash);
+ '''
+ ),
+ ("test_sstate", "METH_NOARGS",
+ '''
+ PyObject *s = PyString_FromString("xyz");
+ /*int sstate = ((PyBytesObject*)s)->ob_sstate;
+ printf("sstate now %d\\n", sstate);*/
+ PyString_InternInPlace(&s);
+ /*sstate = ((PyBytesObject*)s)->ob_sstate;
+ printf("sstate now %d\\n", sstate);*/
+ Py_DECREF(s);
+ return PyBool_FromLong(1);
+ '''),
+ ], prologue='#include <stdlib.h>')
+ res = module.test_hash("xyz")
+ assert res == hash('xyz')
+ # doesn't really test, but if printf is enabled will prove sstate
+ assert module.test_sstate()
+
+ def test_subclass(self):
+ # taken from PyStringArrType_Type in numpy's scalartypes.c.src
+ module = self.import_extension('bar', [
+ ("newsubstr", "METH_O",
+ """
+ PyObject * obj;
+ char * data;
+ int len;
+
+ data = PyString_AS_STRING(args);
+ len = PyString_GET_SIZE(args);
+ if (data == NULL)
+ Py_RETURN_NONE;
+ obj = PyArray_Scalar(data, len);
+ return obj;
+ """),
+ ("get_len", "METH_O",
+ """
+ return PyLong_FromLong(PyObject_Size(args));
+ """),
+ ('has_nb_add', "METH_O",
+ '''
+ if (args->ob_type->tp_as_number == NULL) {
+ Py_RETURN_FALSE;
+ }
+ if (args->ob_type->tp_as_number->nb_add == NULL) {
+ Py_RETURN_FALSE;
+ }
+ Py_RETURN_TRUE;
+ '''),
+ ], prologue="""
+ #include <Python.h>
+ PyTypeObject PyStringArrType_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "bar.string_", /* tp_name*/
+ sizeof(PyBytesObject), /* tp_basicsize*/
+ 0 /* tp_itemsize */
+ };
+
+ static PyObject *
+ stringtype_repr(PyObject *self)
+ {
+ const char *dptr, *ip;
+ int len;
+ PyObject *new;
+
+ ip = dptr = PyString_AS_STRING(self);
+ len = PyString_GET_SIZE(self);
+ dptr += len-1;
+ while(len > 0 && *dptr-- == 0) {
+ len--;
+ }
+ new = PyString_FromStringAndSize(ip, len);
+ if (new == NULL) {
+ return PyString_FromString("");
+ }
+ return new;
+ }
+
+ static PyObject *
+ stringtype_str(PyObject *self)
+ {
+ const char *dptr, *ip;
+ int len;
+ PyObject *new;
+
+ ip = dptr = PyString_AS_STRING(self);
+ len = PyString_GET_SIZE(self);
+ dptr += len-1;
+ while(len > 0 && *dptr-- == 0) {
+ len--;
+ }
+ new = PyString_FromStringAndSize(ip, len);
+ if (new == NULL) {
+ return PyString_FromString("");
+ }
+ return new;
+ }
+
+ PyObject *
+ PyArray_Scalar(char *data, int n)
+ {
+ PyTypeObject *type = &PyStringArrType_Type;
+ PyObject *obj;
+ void *destptr;
+ int itemsize = n;
+ obj = type->tp_alloc(type, itemsize);
+ if (obj == NULL) {
+ return NULL;
+ }
+ destptr = PyString_AS_STRING(obj);
+ ((PyBytesObject *)obj)->ob_shash = -1;
+ memcpy(destptr, data, itemsize);
+ return obj;
+ }
+ """, more_init = '''
+ PyStringArrType_Type.tp_alloc = NULL;
+ PyStringArrType_Type.tp_free = NULL;
+
+ PyStringArrType_Type.tp_repr = stringtype_repr;
+ PyStringArrType_Type.tp_str = stringtype_str;
+ PyStringArrType_Type.tp_flags =
Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE;
+ PyStringArrType_Type.tp_itemsize = sizeof(char);
+ PyStringArrType_Type.tp_base = &PyString_Type;
+ PyStringArrType_Type.tp_hash = PyString_Type.tp_hash;
+ if (PyType_Ready(&PyStringArrType_Type) < 0) INITERROR;
+ ''')
+
+ a = module.newsubstr('abc')
+ assert module.has_nb_add('a') is False
+ assert module.has_nb_add(a) is False
+ assert type(a).__name__ == 'string_'
+ assert a == 'abc'
+ assert 3 == module.get_len(a)
+ b = module.newsubstr('')
+ assert 0 == module.get_len(b)
+
+class TestBytes(BaseApiTest):
+ def test_bytes_resize(self, space):
+ py_str = new_empty_str(space, 10)
+ ar = lltype.malloc(PyObjectP.TO, 1, flavor='raw')
+ py_str.c_ob_sval[0] = 'a'
+ py_str.c_ob_sval[1] = 'b'
+ py_str.c_ob_sval[2] = 'c'
+ ar[0] = rffi.cast(PyObject, py_str)
+ _PyString_Resize(space, ar, 3)
+ py_str = rffi.cast(PyBytesObject, ar[0])
+ assert py_str.c_ob_size == 3
+ assert py_str.c_ob_sval[1] == 'b'
+ assert py_str.c_ob_sval[3] == '\x00'
+ # the same for growing
+ ar[0] = rffi.cast(PyObject, py_str)
+ _PyString_Resize(space, ar, 10)
+ py_str = rffi.cast(PyBytesObject, ar[0])
+ assert py_str.c_ob_size == 10
+ assert py_str.c_ob_sval[1] == 'b'
+ assert py_str.c_ob_sval[10] == '\x00'
+ decref(space, ar[0])
+ lltype.free(ar, flavor='raw')
+
+ def test_string_buffer(self, space):
+ py_str = new_empty_str(space, 10)
+ c_buf = py_str.c_ob_type.c_tp_as_buffer
+ assert c_buf
+ py_obj = rffi.cast(PyObject, py_str)
+ assert generic_cpy_call(space, c_buf.c_bf_getsegcount,
+ py_obj, lltype.nullptr(Py_ssize_tP.TO)) == 1
+ ref = lltype.malloc(Py_ssize_tP.TO, 1, flavor='raw')
+ assert generic_cpy_call(space, c_buf.c_bf_getsegcount,
+ py_obj, ref) == 1
+ assert ref[0] == 10
+ lltype.free(ref, flavor='raw')
+ ref = lltype.malloc(rffi.VOIDPP.TO, 1, flavor='raw')
+ assert generic_cpy_call(space, c_buf.c_bf_getreadbuffer,
+ py_obj, 0, ref) == 10
+ lltype.free(ref, flavor='raw')
+ decref(space, py_obj)
+
+ def test_Concat(self, space):
+ ref = make_ref(space, space.wrap('abc'))
+ ptr = lltype.malloc(PyObjectP.TO, 1, flavor='raw')
+ ptr[0] = ref
+ prev_refcnt = ref.c_ob_refcnt
+ PyString_Concat(space, ptr, space.wrap('def'))
+ assert ref.c_ob_refcnt == prev_refcnt - 1
+ assert space.str_w(from_ref(space, ptr[0])) == 'abcdef'
+ with pytest.raises(OperationError):
+ PyString_Concat(space, ptr, space.w_None)
+ assert not ptr[0]
+ ptr[0] = lltype.nullptr(PyObject.TO)
+ PyString_Concat(space, ptr, space.wrap('def')) # should not crash
+ lltype.free(ptr, flavor='raw')
+
+ def test_ConcatAndDel(self, space):
+ ref1 = make_ref(space, space.wrap('abc'))
+ ref2 = make_ref(space, space.wrap('def'))
+ ptr = lltype.malloc(PyObjectP.TO, 1, flavor='raw')
+ ptr[0] = ref1
+ prev_refcnf = ref2.c_ob_refcnt
+ PyString_ConcatAndDel(space, ptr, ref2)
+ assert space.str_w(from_ref(space, ptr[0])) == 'abcdef'
+ assert ref2.c_ob_refcnt == prev_refcnf - 1
+ decref(space, ptr[0])
+ ptr[0] = lltype.nullptr(PyObject.TO)
+ ref2 = make_ref(space, space.wrap('foo'))
+ prev_refcnf = ref2.c_ob_refcnt
+ PyString_ConcatAndDel(space, ptr, ref2) # should not crash
+ assert ref2.c_ob_refcnt == prev_refcnf - 1
+ lltype.free(ptr, flavor='raw')
+
+ def test_format(self, space):
+ assert "1 2" == space.unwrap(
+ PyString_Format(space, space.wrap('%s %d'), space.wrap((1, 2))))
+
+ def test_asbuffer(self, space):
+ bufp = lltype.malloc(rffi.CCHARPP.TO, 1, flavor='raw')
+ lenp = lltype.malloc(Py_ssize_tP.TO, 1, flavor='raw')
+
+ w_text = space.wrap("text")
+ ref = make_ref(space, w_text)
+ prev_refcnt = ref.c_ob_refcnt
+ assert PyObject_AsCharBuffer(space, ref, bufp, lenp) == 0
+ assert ref.c_ob_refcnt == prev_refcnt
+ assert lenp[0] == 4
+ assert rffi.charp2str(bufp[0]) == 'text'
+ lltype.free(bufp, flavor='raw')
+ lltype.free(lenp, flavor='raw')
+ decref(space, ref)
+
+ def test_intern(self, space):
+ buf = rffi.str2charp("test")
+ w_s1 = PyString_InternFromString(space, buf)
+ w_s2 = PyString_InternFromString(space, buf)
+ rffi.free_charp(buf)
+ assert w_s1 is w_s2
+
+ def test_AsEncodedObject(self, space):
+ ptr = space.wrap('abc')
+
+ errors = rffi.str2charp("strict")
+
+ encoding = rffi.str2charp("hex")
+ res = PyString_AsEncodedObject(space, ptr, encoding, errors)
+ assert space.unwrap(res) == "616263"
+
+ res = PyString_AsEncodedObject(space,
+ ptr, encoding, lltype.nullptr(rffi.CCHARP.TO))
+ assert space.unwrap(res) == "616263"
+ rffi.free_charp(encoding)
+
+ encoding = rffi.str2charp("unknown_encoding")
+ with raises_w(space, LookupError):
+ PyString_AsEncodedObject(space, ptr, encoding, errors)
+ rffi.free_charp(encoding)
+
+ rffi.free_charp(errors)
+
+ NULL = lltype.nullptr(rffi.CCHARP.TO)
+ res = PyString_AsEncodedObject(space, ptr, NULL, NULL)
+ assert space.unwrap(res) == "abc"
+ with raises_w(space, TypeError):
+ PyString_AsEncodedObject(space, space.wrap(2), NULL, NULL)
+
+ def test_AsDecodedObject(self, space):
+ w_str = space.wrap('caf\xe9')
+ encoding = rffi.str2charp("latin-1")
+ w_res = PyString_AsDecodedObject(space, w_str, encoding, None)
+ rffi.free_charp(encoding)
+ assert space.unwrap(w_res) == u"caf\xe9"
+
+ def test_eq(self, space):
+ assert 1 == _PyString_Eq(
+ space, space.wrap("hello"), space.wrap("hello"))
+ assert 0 == _PyString_Eq(
+ space, space.wrap("hello"), space.wrap("world"))
+
+ def test_join(self, space):
+ w_sep = space.wrap('<sep>')
+ w_seq = space.wrap(['a', 'b'])
+ w_joined = _PyString_Join(space, w_sep, w_seq)
+ assert space.unwrap(w_joined) == 'a<sep>b'
diff --git a/pypy/module/cpyext/test/test_capsule.py
b/pypy/module/cpyext/test/test_capsule.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/test/test_capsule.py
@@ -0,0 +1,29 @@
+from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
+
+class AppTestCapsule(AppTestCpythonExtensionBase):
+ def test_capsule_import(self):
+ module = self.import_extension('foo', [
+ ("set_ptr", "METH_O",
+ """
+ PyObject *capsule, *module;
+ void *ptr = PyLong_AsVoidPtr(args);
+ if (PyErr_Occurred()) return NULL;
+ capsule = PyCapsule_New(ptr, "foo._ptr", NULL);
+ if (PyErr_Occurred()) return NULL;
+ module = PyImport_ImportModule("foo");
+ PyModule_AddObject(module, "_ptr", capsule);
+ Py_DECREF(module);
+ if (PyErr_Occurred()) return NULL;
+ Py_RETURN_NONE;
+ """),
+ ("get_ptr", "METH_NOARGS",
+ """
+ void *ptr = PyCapsule_Import("foo._ptr", 0);
+ if (PyErr_Occurred()) return NULL;
+ return PyLong_FromVoidPtr(ptr);
+ """)])
+ module.set_ptr(1234)
+ assert 'capsule object "foo._ptr" at ' in str(module._ptr)
+ import gc; gc.collect()
+ assert module.get_ptr() == 1234
+ del module._ptr
diff --git a/pypy/module/cpyext/test/test_cell.py
b/pypy/module/cpyext/test/test_cell.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/test/test_cell.py
@@ -0,0 +1,20 @@
+from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
+
+
+class AppTestCell(AppTestCpythonExtensionBase):
+ def test_cell_type(self):
+ module = self.import_extension('foo', [
+ ("cell_type", "METH_O",
+ """
+ PyDict_SetItemString(args, "cell", (PyObject*)&PyCell_Type);
+ Py_RETURN_NONE;
+ """)])
+ d = {}
+ module.cell_type(d)
+ def f(o):
+ def g():
+ return o
+ return g
+
+ cell_type = type(f(0).func_closure[0])
+ assert d["cell"] is cell_type
diff --git a/pypy/module/cpyext/test/test_classobject.py
b/pypy/module/cpyext/test/test_classobject.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/test/test_classobject.py
@@ -0,0 +1,93 @@
+from pypy.interpreter.function import Function
+from pypy.module.cpyext.test.test_api import BaseApiTest
+from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
+from pypy.module.cpyext.classobject import (
+ PyClass_Check, PyClass_New, PyInstance_Check, PyInstance_New,
+ PyInstance_NewRaw, _PyInstance_Lookup)
+from pypy.module.cpyext.object import PyObject_GetAttr
+from pypy.module.cpyext.pyobject import get_w_obj_and_decref
+
+class TestClassObject(BaseApiTest):
+ def test_newinstance(self, space):
+ w_class = space.appexec([], """():
+ class C:
+ x = None
+ def __init__(self, *args, **kwargs):
+ self.x = 1
+ self.args = args
+ self.__dict__.update(kwargs)
+ return C
+ """)
+
+ assert PyClass_Check(space, w_class)
+
+ w_instance = PyInstance_NewRaw(space, w_class, None)
+ assert PyInstance_Check(space, w_instance)
+ assert space.getattr(w_instance, space.wrap('x')) is space.w_None
+
+ w_instance = PyInstance_NewRaw(space, w_class, space.wrap(dict(a=3)))
+ assert space.getattr(w_instance, space.wrap('x')) is space.w_None
+ assert space.unwrap(space.getattr(w_instance, space.wrap('a'))) == 3
+
+ w_instance = PyInstance_New(space, w_class,
+ space.wrap((3,)),
space.wrap(dict(y=2)))
+ assert space.unwrap(space.getattr(w_instance, space.wrap('x'))) == 1
+ assert space.unwrap(space.getattr(w_instance, space.wrap('y'))) == 2
+ assert space.unwrap(space.getattr(w_instance, space.wrap('args'))) ==
(3,)
+
+ def test_lookup(self, space):
+ w_instance = space.appexec([], """():
+ class C:
+ def __init__(self):
+ self.x = None
+ def f(self): pass
+ return C()
+ """)
+
+ assert PyInstance_Check(space, w_instance)
+ py_obj = PyObject_GetAttr(space, w_instance, space.wrap('x'))
+ assert get_w_obj_and_decref(space, py_obj) is space.w_None
+ assert _PyInstance_Lookup(space, w_instance, space.wrap('x')) is
space.w_None
+ assert _PyInstance_Lookup(space, w_instance, space.wrap('y')) is None
+
+ # getattr returns a bound method
+ py_obj = PyObject_GetAttr(space, w_instance, space.wrap('f'))
+ assert not isinstance(get_w_obj_and_decref(space, py_obj), Function)
+ # _PyInstance_Lookup returns the raw descriptor
+ assert isinstance(
+ _PyInstance_Lookup(space, w_instance, space.wrap('f')), Function)
+
+ def test_pyclass_new(self, space):
+ w_bases = space.newtuple([])
+ w_dict = space.newdict()
+ w_name = space.wrap("C")
+ w_class = PyClass_New(space, w_bases, w_dict, w_name)
+ assert not space.isinstance_w(w_class, space.w_type)
+ w_instance = space.call_function(w_class)
+ assert PyInstance_Check(space, w_instance)
+ assert space.is_true(space.call_method(space.builtin, "isinstance",
+ w_instance, w_class))
+
+class AppTestStringObject(AppTestCpythonExtensionBase):
+ def test_class_type(self):
+ module = self.import_extension('foo', [
+ ("get_classtype", "METH_NOARGS",
+ """
+ Py_INCREF(&PyClass_Type);
+ return (PyObject*)&PyClass_Type;
+ """)])
+ class C:
+ pass
+ assert module.get_classtype() is type(C)
+
+ def test_pyclass_new_no_bases(self):
+ module = self.import_extension('foo', [
+ ("new_foo", "METH_O",
+ """
+ return PyClass_New(NULL, PyDict_New(), args);
+ """)])
+ FooClass = module.new_foo("FooClass")
+ class Cls1:
+ pass
+ assert type(FooClass) is type(Cls1)
+ assert FooClass.__bases__ == Cls1.__bases__
diff --git a/pypy/module/cpyext/test/test_codecs.py
b/pypy/module/cpyext/test/test_codecs.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/test/test_codecs.py
@@ -0,0 +1,15 @@
+# encoding: iso-8859-15
+from pypy.module.cpyext.test.test_api import BaseApiTest
+from rpython.rtyper.lltypesystem import rffi
+from pypy.module.cpyext.codecs import (
+ PyCodec_IncrementalEncoder, PyCodec_IncrementalDecoder)
+
+class TestCodecs(BaseApiTest):
+ def test_incremental(self, space):
+ utf8 = rffi.str2charp('utf-8')
+ w_encoder = PyCodec_IncrementalEncoder(space, utf8, None)
+ w_encoded = space.call_method(w_encoder, 'encode',
space.wrap(u'späm'))
+ w_decoder = PyCodec_IncrementalDecoder(space, utf8, None)
+ w_decoded = space.call_method(w_decoder, 'decode', w_encoded)
+ assert space.unicode_w(w_decoded) == u'späm'
+ rffi.free_charp(utf8)
diff --git a/pypy/module/cpyext/test/test_complexobject.py
b/pypy/module/cpyext/test/test_complexobject.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/test/test_complexobject.py
@@ -0,0 +1,64 @@
+from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
+from pypy.module.cpyext.test.test_api import BaseApiTest, raises_w
+from pypy.module.cpyext.complexobject import (
+ PyComplex_FromDoubles, PyComplex_RealAsDouble, PyComplex_ImagAsDouble)
+
+class TestComplexObject(BaseApiTest):
+ def test_complexobject(self, space):
+ w_value = PyComplex_FromDoubles(space, 1.2, 3.4)
+ assert space.unwrap(w_value) == 1.2+3.4j
+ assert PyComplex_RealAsDouble(space, w_value) == 1.2
+ assert PyComplex_ImagAsDouble(space, w_value) == 3.4
+
+ assert PyComplex_RealAsDouble(space, space.wrap(42)) == 42
+ assert PyComplex_RealAsDouble(space, space.wrap(1.5)) == 1.5
+ assert PyComplex_ImagAsDouble(space, space.wrap(1.5)) == 0.0
+
+ # cpython accepts anything for PyComplex_ImagAsDouble
+ assert PyComplex_ImagAsDouble(space, space.w_None) == 0.0
+ with raises_w(space, TypeError):
+ PyComplex_RealAsDouble(space, space.w_None)
+
+class AppTestCComplex(AppTestCpythonExtensionBase):
+ def test_AsCComplex(self):
+ module = self.import_extension('foo', [
+ ("as_tuple", "METH_O",
+ """
+ Py_complex c = PyComplex_AsCComplex(args);
+ if (PyErr_Occurred()) return NULL;
+ return Py_BuildValue("dd", c.real, c.imag);
+ """)])
+ assert module.as_tuple(12-34j) == (12, -34)
+ assert module.as_tuple(-3.14) == (-3.14, 0.0)
+ raises(TypeError, module.as_tuple, "12")
+
+ def test_FromCComplex(self):
+ module = self.import_extension('foo', [
+ ("test", "METH_NOARGS",
+ """
+ Py_complex c = {1.2, 3.4};
+ return PyComplex_FromCComplex(c);
+ """)])
+ assert module.test() == 1.2 + 3.4j
+
+ def test_PyComplex_to_WComplex(self):
+ module = self.import_extension('foo', [
+ ("test", "METH_NOARGS",
+ """
+ Py_complex c = {1.2, 3.4};
+ PyObject *obj = PyObject_Malloc(sizeof(PyComplexObject));
+ obj = PyObject_Init(obj, &PyComplex_Type);
+ assert(obj != NULL);
+ ((PyComplexObject *)obj)->cval = c;
+ return obj;
+ """)])
+ assert module.test() == 1.2 + 3.4j
+
+ def test_WComplex_to_PyComplex(self):
+ module = self.import_extension('foo', [
+ ("test", "METH_O",
+ """
+ Py_complex c = ((PyComplexObject *)args)->cval;
+ return Py_BuildValue("dd", c.real, c.imag);
+ """)])
+ assert module.test(1.2 + 3.4j) == (1.2, 3.4)
diff --git a/pypy/module/cpyext/test/test_cparser.py
b/pypy/module/cpyext/test/test_cparser.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/test/test_cparser.py
@@ -0,0 +1,260 @@
+from rpython.flowspace.model import const
+from rpython.flowspace.objspace import build_flow
+from rpython.translator.simplify import simplify_graph
+from rpython.rtyper.lltypesystem import rffi, lltype
+from pypy.module.cpyext.cparser import parse_source, CTypeSpace
+
+def test_configure():
+ decl = """
+ typedef ssize_t Py_ssize_t;
+
+ typedef struct {
+ Py_ssize_t ob_refcnt;
+ Py_ssize_t ob_pypy_link;
+ double ob_fval;
+ } TestFloatObject;
+ """
+ cts = parse_source(decl)
+ TestFloatObject = cts.definitions['TestFloatObject']
+ assert isinstance(TestFloatObject, lltype.Struct)
+ assert TestFloatObject.c_ob_refcnt == rffi.SSIZE_T
+ assert TestFloatObject.c_ob_pypy_link == rffi.SSIZE_T
+ assert TestFloatObject.c_ob_fval == rffi.DOUBLE
+
+def test_simple():
+ decl = "typedef ssize_t Py_ssize_t;"
+ cts = parse_source(decl)
+ assert cts.definitions == {'Py_ssize_t': rffi.SSIZE_T}
+
+def test_macro():
+ decl = """
+ typedef ssize_t Py_ssize_t;
+
+ #define PyObject_HEAD \
+ Py_ssize_t ob_refcnt; \
+ Py_ssize_t ob_pypy_link; \
+
+ typedef struct {
+ PyObject_HEAD
+ double ob_fval;
+ } PyFloatObject;
+ """
+ cts = parse_source(decl)
+ assert 'PyFloatObject' in cts.definitions
+ assert 'PyObject_HEAD' in cts.macros
+
+def test_include():
+ cdef1 = """
+ typedef ssize_t Py_ssize_t;
+
+ #define PyObject_HEAD \
+ Py_ssize_t ob_refcnt; \
+ Py_ssize_t ob_pypy_link; \
+
+ typedef struct {
+ char *name;
+ } Type;
+ """
+ cdef2 = """
+ typedef struct {
+ PyObject_HEAD
+ Py_ssize_t ob_foo;
+ Type *type;
+ } Object;
+ """
+ cts1 = parse_source(cdef1)
+ Type = cts1.definitions['Type']
+ assert isinstance(Type, lltype.Struct)
+ cts2 = parse_source(cdef2, includes=[cts1])
+ assert 'Type' not in cts2.definitions
+ Object = cts2.definitions['Object']
+ assert Object.c_type.TO is Type
+
+def test_multiple_sources():
+ cdef1 = """
+ typedef ssize_t Py_ssize_t;
+
+ #define PyObject_HEAD \
+ Py_ssize_t ob_refcnt; \
+ Py_ssize_t ob_pypy_link; \
+
+ typedef struct {
+ char *name;
+ } Type;
+ """
+ cdef2 = """
+ typedef struct {
+ PyObject_HEAD
+ Py_ssize_t ob_foo;
+ Type *type;
+ } Object;
+ """
+ cts = CTypeSpace()
+ cts.parse_source(cdef1)
+ Type = cts.definitions['Type']
+ assert isinstance(Type, lltype.Struct)
+ assert 'Object' not in cts.definitions
+ cts.parse_source(cdef2)
+ Object = cts.definitions['Object']
+ assert Object.c_type.TO is Type
+
+def test_incomplete():
+ cdef = """
+ typedef ssize_t Py_ssize_t;
+
+ typedef struct {
+ Py_ssize_t ob_refcnt;
+ Py_ssize_t ob_pypy_link;
+ struct _typeobject *ob_type;
+ } Object;
+
+ typedef struct {
+ void *buf;
+ Object *obj;
+ } Buffer;
+
+ """
+ cts = parse_source(cdef)
+ Object = cts.gettype('Object')
+ assert isinstance(Object, lltype.Struct)
+
+def test_recursive():
+ cdef = """
+ typedef ssize_t Py_ssize_t;
+
+ typedef struct {
+ Py_ssize_t ob_refcnt;
+ Py_ssize_t ob_pypy_link;
+ struct _typeobject *ob_type;
+ } Object;
+
+ typedef struct {
+ void *buf;
+ Object *obj;
+ } Buffer;
+
+ typedef struct _typeobject {
+ Object *obj;
+ } Type;
+ """
+ cts = parse_source(cdef)
+ Object = cts.definitions['Object']
+ assert isinstance(Object, lltype.Struct)
+ hash(Object)
+
+def test_nested_struct():
+ cdef = """
+ typedef struct {
+ int x;
+ } foo;
+ typedef struct {
+ foo y;
+ } bar;
+ """
+ cts = parse_source(cdef)
+ bar = cts.gettype('bar')
+ assert isinstance(bar, lltype.Struct)
+ hash(bar) # bar is hashable
+
+def test_const():
+ cdef = """
+ typedef struct {
+ const char * const foo;
+ } bar;
+ """
+ cts = parse_source(cdef)
+ assert cts.definitions['bar'].c_foo == rffi.CONST_CCHARP != rffi.CCHARP
+
+def test_gettype():
+ decl = """
+ typedef ssize_t Py_ssize_t;
+
+ #define PyObject_HEAD \
+ Py_ssize_t ob_refcnt; \
+ Py_ssize_t ob_pypy_link; \
+
+ typedef struct {
+ PyObject_HEAD
+ double ob_fval;
+ } TestFloatObject;
+ """
+ cts = parse_source(decl)
+ assert cts.gettype('Py_ssize_t') == rffi.SSIZE_T
+ assert cts.gettype('TestFloatObject *').TO.c_ob_refcnt == rffi.SSIZE_T
+ assert cts.cast('Py_ssize_t', 42) == rffi.cast(rffi.SSIZE_T, 42)
+
+def test_parse_funcdecl():
+ decl = """
+ typedef ssize_t Py_ssize_t;
+
+ #define PyObject_HEAD \
+ Py_ssize_t ob_refcnt; \
+ Py_ssize_t ob_pypy_link; \
+
+ typedef struct {
+ PyObject_HEAD
+ double ob_fval;
+ } TestFloatObject;
+
+ typedef TestFloatObject* (*func_t)(int, int);
+ """
+ cts = parse_source(decl)
+ func_decl = cts.parse_func("func_t * some_func(TestFloatObject*)")
+ assert func_decl.name == 'some_func'
+ assert func_decl.get_llresult(cts) == cts.gettype('func_t*')
+ assert func_decl.get_llargs(cts) == [cts.gettype('TestFloatObject *')]
+
+def test_write_func():
+ from ..api import ApiFunction
+ from rpython.translator.c.database import LowLevelDatabase
+ db = LowLevelDatabase()
+ cdef = """
+ typedef ssize_t Py_ssize_t;
+ """
+ cts = parse_source(cdef)
+ cdecl = "Py_ssize_t * some_func(Py_ssize_t*)"
+ decl = cts.parse_func(cdecl)
+ api_function = ApiFunction(
+ decl.get_llargs(cts), decl.get_llresult(cts), lambda space, x: None,
+ cdecl=decl)
+ assert (api_function.get_api_decl('some_func', db) ==
+ "PyAPI_FUNC(Py_ssize_t *) some_func(Py_ssize_t * arg0);")
+
+
+def test_wchar_t():
+ cdef = """
+ typedef struct { wchar_t* x; } test;
+ """
+ cts = parse_source(cdef, headers=['stddef.h'])
+ obj = lltype.malloc(cts.gettype('test'), flavor='raw')
+ obj.c_x = cts.cast('wchar_t*', 0)
+ obj.c_x = lltype.nullptr(rffi.CWCHARP.TO)
+ lltype.free(obj, flavor='raw')
+
+
+def test_translate_cast():
+ cdef = "typedef ssize_t Py_ssize_t;"
+ cts = parse_source(cdef)
+
+ def f():
+ return cts.cast('Py_ssize_t*', 0)
+ graph = build_flow(f)
+ simplify_graph(graph)
+ assert len(graph.startblock.operations) == 1
+ op = graph.startblock.operations[0]
+ assert op.args[0] == const(rffi.cast)
+ assert op.args[1].value is cts.gettype('Py_ssize_t*')
+
+def test_translate_gettype():
+ cdef = "typedef ssize_t Py_ssize_t;"
+ cts = parse_source(cdef)
+
+ def f():
+ return cts.gettype('Py_ssize_t*')
+ graph = build_flow(f)
+ simplify_graph(graph)
+ # Check that the result is constant-folded
+ assert graph.startblock.operations == []
+ [link] = graph.startblock.exits
+ assert link.target is graph.returnblock
+ assert link.args[0] == const(rffi.CArrayPtr(rffi.SSIZE_T))
diff --git a/pypy/module/cpyext/test/test_datetime.py
b/pypy/module/cpyext/test/test_datetime.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/test/test_datetime.py
@@ -0,0 +1,354 @@
+import pytest
+
+from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
+from pypy.module.cpyext.test.test_api import BaseApiTest
+from pypy.module.cpyext.cdatetime import *
+from pypy.module.cpyext.cdatetime import (
+ _PyDateTime_Import, _PyDateTime_FromDateAndTime, _PyDate_FromDate,
+ _PyTime_FromTime, _PyDelta_FromDelta)
+import datetime
+
+class TestDatetime(BaseApiTest):
+ def test_date(self, space):
+ date_api = _PyDateTime_Import(space)
+ w_date = _PyDate_FromDate(space, 2010, 06, 03, date_api.c_DateType)
+ assert space.unwrap(space.str(w_date)) == '2010-06-03'
+
+ assert PyDate_Check(space, w_date)
+ assert PyDate_CheckExact(space, w_date)
+
+ assert PyDateTime_GET_YEAR(space, w_date) == 2010
+ assert PyDateTime_GET_MONTH(space, w_date) == 6
+ assert PyDateTime_GET_DAY(space, w_date) == 3
+
+ def test_time(self, space):
+ date_api = _PyDateTime_Import(space)
+ w_time = _PyTime_FromTime(
+ space, 23, 15, 40, 123456, space.w_None, date_api.c_TimeType)
+ assert space.unwrap(space.str(w_time)) == '23:15:40.123456'
+
+ assert PyTime_Check(space, w_time)
+ assert PyTime_CheckExact(space, w_time)
+
+ assert PyDateTime_TIME_GET_HOUR(space, w_time) == 23
+ assert PyDateTime_TIME_GET_MINUTE(space, w_time) == 15
+ assert PyDateTime_TIME_GET_SECOND(space, w_time) == 40
+ assert PyDateTime_TIME_GET_MICROSECOND(space, w_time) == 123456
+
+ def test_datetime(self, space):
+ date_api = _PyDateTime_Import(space)
+ w_date = _PyDateTime_FromDateAndTime(
+ space, 2010, 06, 03, 23, 15, 40, 123456, space.w_None,
+ date_api.c_DateTimeType)
+ assert space.unwrap(space.str(w_date)) == '2010-06-03 23:15:40.123456'
+
+ assert PyDateTime_Check(space, w_date)
+ assert PyDateTime_CheckExact(space, w_date)
+ assert PyDate_Check(space, w_date)
+ assert not PyDate_CheckExact(space, w_date)
+
+ assert PyDateTime_GET_YEAR(space, w_date) == 2010
+ assert PyDateTime_GET_MONTH(space, w_date) == 6
+ assert PyDateTime_GET_DAY(space, w_date) == 3
+ assert PyDateTime_DATE_GET_HOUR(space, w_date) == 23
+ assert PyDateTime_DATE_GET_MINUTE(space, w_date) == 15
+ assert PyDateTime_DATE_GET_SECOND(space, w_date) == 40
+ assert PyDateTime_DATE_GET_MICROSECOND(space, w_date) == 123456
+
+ def test_delta(self, space):
+ date_api = _PyDateTime_Import(space)
+ w_delta = space.appexec(
+ [space.wrap(3), space.wrap(15)], """(days, seconds):
+ from datetime import timedelta
+ return timedelta(days, seconds)
+ """)
+ assert PyDelta_Check(space, w_delta)
+ assert PyDelta_CheckExact(space, w_delta)
+
+ w_delta = _PyDelta_FromDelta(space, 10, 20, 30, True,
date_api.c_DeltaType)
+ assert PyDelta_Check(space, w_delta)
+ assert PyDelta_CheckExact(space, w_delta)
+
+ assert PyDateTime_DELTA_GET_DAYS(space, w_delta) == 10
+ assert PyDateTime_DELTA_GET_SECONDS(space, w_delta) == 20
+ assert PyDateTime_DELTA_GET_MICROSECONDS(space, w_delta) == 30
+
+ def test_fromtimestamp(self, space):
+ w_args = space.wrap((0,))
+ w_date = PyDate_FromTimestamp(space, w_args)
+ date = datetime.date.fromtimestamp(0)
+ assert space.unwrap(space.str(w_date)) == str(date)
+
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit