[pypy-commit] pypy unicode-utf8: merge default
fijal
pypy.commits at gmail.com
Thu Nov 23 10:46:47 EST 2017
Author: fijal
Branch: unicode-utf8
Changeset: r93144:177352fb8cf4
Date: 2017-11-23 16:46 +0100
http://bitbucket.org/pypy/pypy/changeset/177352fb8cf4/
Log: merge default
diff too long, truncating to 2000 out of 7577 lines
diff --git a/.hgignore b/.hgignore
--- a/.hgignore
+++ b/.hgignore
@@ -71,6 +71,8 @@
^lib_pypy/.+.c$
^lib_pypy/.+.o$
^lib_pypy/.+.so$
+^lib_pypy/.+.pyd$
+^lib_pypy/Release/
^pypy/doc/discussion/.+\.html$
^include/.+\.h$
^include/.+\.inl$
diff --git a/extra_tests/requirements.txt b/extra_tests/requirements.txt
new file mode 100644
--- /dev/null
+++ b/extra_tests/requirements.txt
@@ -0,0 +1,2 @@
+pytest
+hypothesis
diff --git a/extra_tests/test_bytes.py b/extra_tests/test_bytes.py
new file mode 100644
--- /dev/null
+++ b/extra_tests/test_bytes.py
@@ -0,0 +1,84 @@
+from hypothesis import strategies as st
+from hypothesis import given, example
+
+st_bytestring = st.binary() | st.binary().map(bytearray)
+
+ at given(st_bytestring, st_bytestring, st_bytestring)
+def test_find(u, prefix, suffix):
+ s = prefix + u + suffix
+ assert 0 <= s.find(u) <= len(prefix)
+ assert s.find(u, len(prefix), len(s) - len(suffix)) == len(prefix)
+
+ at given(st_bytestring, st_bytestring, st_bytestring)
+def test_index(u, prefix, suffix):
+ s = prefix + u + suffix
+ assert 0 <= s.index(u) <= len(prefix)
+ assert s.index(u, len(prefix), len(s) - len(suffix)) == len(prefix)
+
+ at given(st_bytestring, st_bytestring, st_bytestring)
+def test_rfind(u, prefix, suffix):
+ s = prefix + u + suffix
+ assert s.rfind(u) >= len(prefix)
+ assert s.rfind(u, len(prefix), len(s) - len(suffix)) == len(prefix)
+
+ at given(st_bytestring, st_bytestring, st_bytestring)
+def test_rindex(u, prefix, suffix):
+ s = prefix + u + suffix
+ assert s.rindex(u) >= len(prefix)
+ assert s.rindex(u, len(prefix), len(s) - len(suffix)) == len(prefix)
+
+def adjust_indices(u, start, end):
+ if end < 0:
+ end = max(end + len(u), 0)
+ else:
+ end = min(end, len(u))
+ if start < 0:
+ start = max(start + len(u), 0)
+ return start, end
+
+ at given(st_bytestring, st_bytestring)
+def test_startswith_basic(u, v):
+ assert u.startswith(v) is (u[:len(v)] == v)
+
+ at example(b'x', b'', 1)
+ at example(b'x', b'', 2)
+ at given(st_bytestring, st_bytestring, st.integers())
+def test_startswith_start(u, v, start):
+ expected = u[start:].startswith(v) if v else (start <= len(u))
+ assert u.startswith(v, start) is expected
+
+ at example(b'x', b'', 1, 0)
+ at example(b'xx', b'', -1, 0)
+ at given(st_bytestring, st_bytestring, st.integers(), st.integers())
+def test_startswith_3(u, v, start, end):
+ if v:
+ expected = u[start:end].startswith(v)
+ else: # CPython leaks implementation details in this case
+ start0, end0 = adjust_indices(u, start, end)
+ expected = start0 <= len(u) and start0 <= end0
+ assert u.startswith(v, start, end) is expected
+
+ at given(st_bytestring, st_bytestring)
+def test_endswith_basic(u, v):
+ if len(v) > len(u):
+ assert u.endswith(v) is False
+ else:
+ assert u.endswith(v) is (u[len(u) - len(v):] == v)
+
+ at example(b'x', b'', 1)
+ at example(b'x', b'', 2)
+ at given(st_bytestring, st_bytestring, st.integers())
+def test_endswith_2(u, v, start):
+ expected = u[start:].endswith(v) if v else (start <= len(u))
+ assert u.endswith(v, start) is expected
+
+ at example(b'x', b'', 1, 0)
+ at example(b'xx', b'', -1, 0)
+ at given(st_bytestring, st_bytestring, st.integers(), st.integers())
+def test_endswith_3(u, v, start, end):
+ if v:
+ expected = u[start:end].endswith(v)
+ else: # CPython leaks implementation details in this case
+ start0, end0 = adjust_indices(u, start, end)
+ expected = start0 <= len(u) and start0 <= end0
+ assert u.endswith(v, start, end) is expected
diff --git a/extra_tests/test_unicode.py b/extra_tests/test_unicode.py
--- a/extra_tests/test_unicode.py
+++ b/extra_tests/test_unicode.py
@@ -1,3 +1,4 @@
+import sys
import pytest
from hypothesis import strategies as st
from hypothesis import given, settings, example
@@ -32,3 +33,89 @@
@given(s=st.text())
def test_composition(s, norm1, norm2, norm3):
assert normalize(norm2, normalize(norm1, s)) == normalize(norm3, s)
+
+ at given(st.text(), st.text(), st.text())
+def test_find(u, prefix, suffix):
+ s = prefix + u + suffix
+ assert 0 <= s.find(u) <= len(prefix)
+ assert s.find(u, len(prefix), len(s) - len(suffix)) == len(prefix)
+
+ at given(st.text(), st.text(), st.text())
+def test_index(u, prefix, suffix):
+ s = prefix + u + suffix
+ assert 0 <= s.index(u) <= len(prefix)
+ assert s.index(u, len(prefix), len(s) - len(suffix)) == len(prefix)
+
+ at given(st.text(), st.text(), st.text())
+def test_rfind(u, prefix, suffix):
+ s = prefix + u + suffix
+ assert s.rfind(u) >= len(prefix)
+ assert s.rfind(u, len(prefix), len(s) - len(suffix)) == len(prefix)
+
+ at given(st.text(), st.text(), st.text())
+def test_rindex(u, prefix, suffix):
+ s = prefix + u + suffix
+ assert s.rindex(u) >= len(prefix)
+ assert s.rindex(u, len(prefix), len(s) - len(suffix)) == len(prefix)
+
+def adjust_indices(u, start, end):
+ if end < 0:
+ end = max(end + len(u), 0)
+ else:
+ end = min(end, len(u))
+ if start < 0:
+ start = max(start + len(u), 0)
+ return start, end
+
+ at given(st.text(), st.text())
+def test_startswith_basic(u, v):
+ assert u.startswith(v) is (u[:len(v)] == v)
+
+ at example(u'x', u'', 1)
+ at example(u'x', u'', 2)
+ at given(st.text(), st.text(), st.integers())
+def test_startswith_2(u, v, start):
+ if v or sys.version_info[0] == 2:
+ expected = u[start:].startswith(v)
+ else: # CPython leaks implementation details in this case
+ expected = start <= len(u)
+ assert u.startswith(v, start) is expected
+
+ at example(u'x', u'', 1, 0)
+ at example(u'xx', u'', -1, 0)
+ at given(st.text(), st.text(), st.integers(), st.integers())
+def test_startswith_3(u, v, start, end):
+ if v or sys.version_info[0] == 2:
+ expected = u[start:end].startswith(v)
+ else: # CPython leaks implementation details in this case
+ start0, end0 = adjust_indices(u, start, end)
+ expected = start0 <= len(u) and start0 <= end0
+ assert u.startswith(v, start, end) is expected
+
+ at given(st.text(), st.text())
+def test_endswith_basic(u, v):
+ if len(v) > len(u):
+ assert u.endswith(v) is False
+ else:
+ assert u.endswith(v) is (u[len(u) - len(v):] == v)
+
+ at example(u'x', u'', 1)
+ at example(u'x', u'', 2)
+ at given(st.text(), st.text(), st.integers())
+def test_endswith_2(u, v, start):
+ if v or sys.version_info[0] == 2:
+ expected = u[start:].endswith(v)
+ else: # CPython leaks implementation details in this case
+ expected = start <= len(u)
+ assert u.endswith(v, start) is expected
+
+ at example(u'x', u'', 1, 0)
+ at example(u'xx', u'', -1, 0)
+ at given(st.text(), st.text(), st.integers(), st.integers())
+def test_endswith_3(u, v, start, end):
+ if v or sys.version_info[0] == 2:
+ expected = u[start:end].endswith(v)
+ else: # CPython leaks implementation details in this case
+ start0, end0 = adjust_indices(u, start, end)
+ expected = start0 <= len(u) and start0 <= end0
+ assert u.endswith(v, start, end) is expected
diff --git a/lib-python/2.7/ctypes/__init__.py b/lib-python/2.7/ctypes/__init__.py
--- a/lib-python/2.7/ctypes/__init__.py
+++ b/lib-python/2.7/ctypes/__init__.py
@@ -360,14 +360,15 @@
self._FuncPtr = _FuncPtr
if handle is None:
- if flags & _FUNCFLAG_CDECL:
- pypy_dll = _ffi.CDLL(name, mode)
- else:
- pypy_dll = _ffi.WinDLL(name, mode)
- self.__pypy_dll__ = pypy_dll
- handle = int(pypy_dll)
- if _sys.maxint > 2 ** 32:
- handle = int(handle) # long -> int
+ handle = 0
+ if flags & _FUNCFLAG_CDECL:
+ pypy_dll = _ffi.CDLL(name, mode, handle)
+ else:
+ pypy_dll = _ffi.WinDLL(name, mode, handle)
+ self.__pypy_dll__ = pypy_dll
+ handle = int(pypy_dll)
+ if _sys.maxint > 2 ** 32:
+ handle = int(handle) # long -> int
self._handle = handle
def __repr__(self):
diff --git a/lib-python/2.7/inspect.py b/lib-python/2.7/inspect.py
--- a/lib-python/2.7/inspect.py
+++ b/lib-python/2.7/inspect.py
@@ -40,6 +40,10 @@
import linecache
from operator import attrgetter
from collections import namedtuple
+try:
+ from cpyext import is_cpyext_function as _is_cpyext_function
+except ImportError:
+ _is_cpyext_function = lambda obj: False
# These constants are from Include/code.h.
CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, CO_VARKEYWORDS = 0x1, 0x2, 0x4, 0x8
@@ -230,7 +234,7 @@
__doc__ documentation string
__name__ original name of this function or method
__self__ instance to which a method is bound, or None"""
- return isinstance(object, types.BuiltinFunctionType)
+ return isinstance(object, types.BuiltinFunctionType) or _is_cpyext_function(object)
def isroutine(object):
"""Return true if the object is any kind of function or method."""
diff --git a/lib-python/2.7/test/test_urllib2net.py b/lib-python/2.7/test/test_urllib2net.py
--- a/lib-python/2.7/test/test_urllib2net.py
+++ b/lib-python/2.7/test/test_urllib2net.py
@@ -286,7 +286,7 @@
self.assertEqual(u.fp._sock.fp._sock.gettimeout(), 120)
u.close()
- FTP_HOST = 'ftp://ftp.debian.org/debian/'
+ FTP_HOST = 'ftp://www.pythontest.net/'
def test_ftp_basic(self):
self.assertIsNone(socket.getdefaulttimeout())
diff --git a/lib-python/2.7/warnings.py b/lib-python/2.7/warnings.py
--- a/lib-python/2.7/warnings.py
+++ b/lib-python/2.7/warnings.py
@@ -43,11 +43,12 @@
unicodetype = unicode
except NameError:
unicodetype = ()
+ template = "%s: %s: %s\n"
try:
message = str(message)
except UnicodeEncodeError:
- pass
- s = "%s: %s: %s\n" % (lineno, category.__name__, message)
+ template = unicode(template)
+ s = template % (lineno, category.__name__, message)
line = linecache.getline(filename, lineno) if line is None else line
if line:
line = line.strip()
diff --git a/lib_pypy/_ctypes/array.py b/lib_pypy/_ctypes/array.py
--- a/lib_pypy/_ctypes/array.py
+++ b/lib_pypy/_ctypes/array.py
@@ -8,60 +8,63 @@
class ArrayMeta(_CDataMeta):
def __new__(self, name, cls, typedict):
res = type.__new__(self, name, cls, typedict)
- if '_type_' in typedict:
- ffiarray = _rawffi.Array(typedict['_type_']._ffishape_)
- res._ffiarray = ffiarray
- subletter = getattr(typedict['_type_'], '_type_', None)
- if subletter == 'c':
- def getvalue(self):
- return _rawffi.charp2string(self._buffer.buffer,
- self._length_)
- def setvalue(self, val):
- # we don't want to have buffers here
- if len(val) > self._length_:
- raise ValueError("%r too long" % (val,))
- if isinstance(val, str):
- _rawffi.rawstring2charp(self._buffer.buffer, val)
- else:
- for i in range(len(val)):
- self[i] = val[i]
- if len(val) < self._length_:
- self._buffer[len(val)] = '\x00'
- res.value = property(getvalue, setvalue)
- def getraw(self):
- return _rawffi.charp2rawstring(self._buffer.buffer,
- self._length_)
+ if cls == (_CData,): # this is the Array class defined below
+ res._ffiarray = None
+ return res
+ if not hasattr(res, '_length_') or not isinstance(res._length_, int):
+ raise AttributeError(
+ "class must define a '_length_' attribute, "
+ "which must be a positive integer")
+ ffiarray = res._ffiarray = _rawffi.Array(res._type_._ffishape_)
+ subletter = getattr(res._type_, '_type_', None)
+ if subletter == 'c':
+ def getvalue(self):
+ return _rawffi.charp2string(self._buffer.buffer,
+ self._length_)
+ def setvalue(self, val):
+ # we don't want to have buffers here
+ if len(val) > self._length_:
+ raise ValueError("%r too long" % (val,))
+ if isinstance(val, str):
+ _rawffi.rawstring2charp(self._buffer.buffer, val)
+ else:
+ for i in range(len(val)):
+ self[i] = val[i]
+ if len(val) < self._length_:
+ self._buffer[len(val)] = b'\x00'
+ res.value = property(getvalue, setvalue)
- def setraw(self, buffer):
- if len(buffer) > self._length_:
- raise ValueError("%r too long" % (buffer,))
- _rawffi.rawstring2charp(self._buffer.buffer, buffer)
- res.raw = property(getraw, setraw)
- elif subletter == 'u':
- def getvalue(self):
- return _rawffi.wcharp2unicode(self._buffer.buffer,
- self._length_)
+ def getraw(self):
+ return _rawffi.charp2rawstring(self._buffer.buffer,
+ self._length_)
- def setvalue(self, val):
- # we don't want to have buffers here
- if len(val) > self._length_:
- raise ValueError("%r too long" % (val,))
- if isinstance(val, unicode):
- target = self._buffer
- else:
- target = self
- for i in range(len(val)):
- target[i] = val[i]
- if len(val) < self._length_:
- target[len(val)] = u'\x00'
- res.value = property(getvalue, setvalue)
-
- if '_length_' in typedict:
- res._ffishape_ = (ffiarray, typedict['_length_'])
- res._fficompositesize_ = res._sizeofinstances()
- else:
- res._ffiarray = None
+ def setraw(self, buffer):
+ if len(buffer) > self._length_:
+ raise ValueError("%r too long" % (buffer,))
+ _rawffi.rawstring2charp(self._buffer.buffer, buffer)
+ res.raw = property(getraw, setraw)
+ elif subletter == 'u':
+ def getvalue(self):
+ return _rawffi.wcharp2unicode(self._buffer.buffer,
+ self._length_)
+
+ def setvalue(self, val):
+ # we don't want to have buffers here
+ if len(val) > self._length_:
+ raise ValueError("%r too long" % (val,))
+ if isinstance(val, unicode):
+ target = self._buffer
+ else:
+ target = self
+ for i in range(len(val)):
+ target[i] = val[i]
+ if len(val) < self._length_:
+ target[len(val)] = u'\x00'
+ res.value = property(getvalue, setvalue)
+
+ res._ffishape_ = (ffiarray, res._length_)
+ res._fficompositesize_ = res._sizeofinstances()
return res
from_address = cdata_from_address
@@ -156,7 +159,7 @@
l = [self[i] for i in range(start, stop, step)]
letter = getattr(self._type_, '_type_', None)
if letter == 'c':
- return "".join(l)
+ return b"".join(l)
if letter == 'u':
return u"".join(l)
return l
diff --git a/lib_pypy/_ctypes/basics.py b/lib_pypy/_ctypes/basics.py
--- a/lib_pypy/_ctypes/basics.py
+++ b/lib_pypy/_ctypes/basics.py
@@ -176,6 +176,10 @@
def _get_buffer_value(self):
return self._buffer[0]
+ def _copy_to(self, addr):
+ target = type(self).from_address(addr)._buffer
+ target[0] = self._get_buffer_value()
+
def _to_ffi_param(self):
if self.__class__._is_pointer_like():
return self._get_buffer_value()
diff --git a/lib_pypy/_ctypes/pointer.py b/lib_pypy/_ctypes/pointer.py
--- a/lib_pypy/_ctypes/pointer.py
+++ b/lib_pypy/_ctypes/pointer.py
@@ -114,7 +114,9 @@
cobj = self._type_.from_param(value)
if ensure_objects(cobj) is not None:
store_reference(self, index, cobj._objects)
- self._subarray(index)[0] = cobj._get_buffer_value()
+ address = self._buffer[0]
+ address += index * sizeof(self._type_)
+ cobj._copy_to(address)
def __nonzero__(self):
return self._buffer[0] != 0
diff --git a/lib_pypy/_ctypes/structure.py b/lib_pypy/_ctypes/structure.py
--- a/lib_pypy/_ctypes/structure.py
+++ b/lib_pypy/_ctypes/structure.py
@@ -291,6 +291,11 @@
def _get_buffer_value(self):
return self._buffer.buffer
+ def _copy_to(self, addr):
+ from ctypes import memmove
+ origin = self._get_buffer_value()
+ memmove(addr, origin, self._fficompositesize_)
+
def _to_ffi_param(self):
return self._buffer
diff --git a/lib_pypy/_ctypes_test.py b/lib_pypy/_ctypes_test.py
--- a/lib_pypy/_ctypes_test.py
+++ b/lib_pypy/_ctypes_test.py
@@ -21,5 +21,11 @@
with fp:
imp.load_module('_ctypes_test', fp, filename, description)
except ImportError:
+ if os.name == 'nt':
+ # hack around finding compilers on win32
+ try:
+ import setuptools
+ except ImportError:
+ pass
print('could not find _ctypes_test in %s' % output_dir)
_pypy_testcapi.compile_shared('_ctypes_test.c', '_ctypes_test', output_dir)
diff --git a/lib_pypy/_sqlite3.py b/lib_pypy/_sqlite3.py
--- a/lib_pypy/_sqlite3.py
+++ b/lib_pypy/_sqlite3.py
@@ -1027,21 +1027,25 @@
if '\0' in sql:
raise ValueError("the query contains a null character")
- first_word = sql.lstrip().split(" ")[0].upper()
- if first_word == "":
+
+ if sql:
+ first_word = sql.lstrip().split()[0].upper()
+ if first_word == '':
+ self._type = _STMT_TYPE_INVALID
+ if first_word == "SELECT":
+ self._type = _STMT_TYPE_SELECT
+ elif first_word == "INSERT":
+ self._type = _STMT_TYPE_INSERT
+ elif first_word == "UPDATE":
+ self._type = _STMT_TYPE_UPDATE
+ elif first_word == "DELETE":
+ self._type = _STMT_TYPE_DELETE
+ elif first_word == "REPLACE":
+ self._type = _STMT_TYPE_REPLACE
+ else:
+ self._type = _STMT_TYPE_OTHER
+ else:
self._type = _STMT_TYPE_INVALID
- elif first_word == "SELECT":
- self._type = _STMT_TYPE_SELECT
- elif first_word == "INSERT":
- self._type = _STMT_TYPE_INSERT
- elif first_word == "UPDATE":
- self._type = _STMT_TYPE_UPDATE
- elif first_word == "DELETE":
- self._type = _STMT_TYPE_DELETE
- elif first_word == "REPLACE":
- self._type = _STMT_TYPE_REPLACE
- else:
- self._type = _STMT_TYPE_OTHER
if isinstance(sql, unicode):
sql = sql.encode('utf-8')
diff --git a/lib_pypy/_testcapi.py b/lib_pypy/_testcapi.py
--- a/lib_pypy/_testcapi.py
+++ b/lib_pypy/_testcapi.py
@@ -16,4 +16,10 @@
with fp:
imp.load_module('_testcapi', fp, filename, description)
except ImportError:
+ if os.name == 'nt':
+ # hack around finding compilers on win32
+ try:
+ import setuptools
+ except ImportError:
+ pass
_pypy_testcapi.compile_shared(cfile, '_testcapi', output_dir)
diff --git a/lib_pypy/_tkinter/app.py b/lib_pypy/_tkinter/app.py
--- a/lib_pypy/_tkinter/app.py
+++ b/lib_pypy/_tkinter/app.py
@@ -119,7 +119,7 @@
tklib.TCL_GLOBAL_ONLY)
# This is used to get the application class for Tk 4.1 and up
- argv0 = className.lower()
+ argv0 = className.lower().encode('ascii')
tklib.Tcl_SetVar(self.interp, "argv0", argv0,
tklib.TCL_GLOBAL_ONLY)
@@ -180,6 +180,9 @@
if err == tklib.TCL_ERROR:
self.raiseTclError()
+ def interpaddr(self):
+ return int(tkffi.cast('size_t', self.interp))
+
def _var_invoke(self, func, *args, **kwargs):
if self.threaded and self.thread_id != tklib.Tcl_GetCurrentThread():
# The current thread is not the interpreter thread.
diff --git a/pypy/doc/faq.rst b/pypy/doc/faq.rst
--- a/pypy/doc/faq.rst
+++ b/pypy/doc/faq.rst
@@ -182,6 +182,57 @@
technical difficulties.
+What about numpy, numpypy, micronumpy?
+--------------------------------------
+
+Way back in 2011, the PyPy team `started to reimplement`_ numpy in PyPy. It
+has two pieces:
+
+ * the builtin module :source:`pypy/module/micronumpy`: this is written in
+ RPython and roughly covers the content of the ``numpy.core.multiarray``
+ module. Confusingly enough, this is available in PyPy under the name
+ ``_numpypy``. It is included by default in all the official releases of
+ PyPy (but it might be dropped in the future).
+
+ * a fork_ of the official numpy repository maintained by us and informally
+ called ``numpypy``: even more confusing, the name of the repo on bitbucket
+ is ``numpy``. The main difference with the upstream numpy, is that it is
+ based on the micronumpy module written in RPython, instead of of
+ ``numpy.core.multiarray`` which is written in C.
+
+Moreover, it is also possible to install the upstream version of ``numpy``:
+its core is written in C and it runs on PyPy under the cpyext compatibility
+layer. This is what you get if you do ``pypy -m pip install numpy``.
+
+
+Should I install numpy or numpypy?
+-----------------------------------
+
+TL;DR version: you should use numpy. You can install it by doing ``pypy -m pip
+install numpy``. You might also be interested in using the experimental `PyPy
+binary wheels`_ to save compilation time.
+
+The upstream ``numpy`` is written in C, and runs under the cpyext
+compatibility layer. Nowadays, cpyext is mature enough that you can simply
+use the upstream ``numpy``, since it passes 99.9% of the test suite. At the
+moment of writing (October 2017) the main drawback of ``numpy`` is that cpyext
+is infamously slow, and thus it has worse performance compared to
+``numpypy``. However, we are actively working on improving it, as we expect to
+reach the same speed, eventually.
+
+On the other hand, ``numpypy`` is more JIT-friendly and very fast to call,
+since it is written in RPython: but it is a reimplementation, and it's hard to
+be completely compatible: over the years the project slowly matured and
+eventually it was able to call out to the LAPACK and BLAS libraries to speed
+matrix calculations, and reached around an 80% parity with the upstream
+numpy. However, 80% is far from 100%. Since cpyext/numpy compatibility is
+progressing fast, we have discontinued support for ``numpypy``.
+
+.. _`started to reimplement`: https://morepypy.blogspot.co.il/2011/05/numpy-in-pypy-status-and-roadmap.html
+.. _fork: https://bitbucket.org/pypy/numpy
+.. _`PyPy binary wheels`: https://github.com/antocuni/pypy-wheels
+
+
Is PyPy more clever than CPython about Tail Calls?
--------------------------------------------------
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
@@ -10,3 +10,19 @@
.. branch: docs-osx-brew-openssl
+.. branch: keep-debug-symbols
+Add a smartstrip tool, which can optionally keep the debug symbols in a
+separate file, instead of just stripping them away. Use it in packaging
+
+.. branch: bsd-patches
+Fix failures on FreeBSD, contributed by David Naylor as patches on the issue
+tracker (issues 2694, 2695, 2696, 2697)
+
+.. branch: run-extra-tests
+Run extra_tests/ in buildbot
+
+.. branch: vmprof-0.4.10
+Upgrade the _vmprof backend to vmprof 0.4.10
+
+.. branch: fix-vmprof-stacklet-switch
+Fix a vmprof+continulets (i.e. greenelts, eventlet, gevent, ...)
diff --git a/pypy/goal/getnightly.py b/pypy/goal/getnightly.py
--- a/pypy/goal/getnightly.py
+++ b/pypy/goal/getnightly.py
@@ -15,7 +15,7 @@
arch = 'linux'
cmd = 'wget "%s"'
TAR_OPTIONS += ' --wildcards'
- binfiles = "'*/bin/pypy' '*/bin/libpypy-c.so'"
+ binfiles = "'*/bin/pypy*' '*/bin/libpypy-c.so*'"
if os.uname()[-1].startswith('arm'):
arch += '-armhf-raspbian'
elif sys.platform.startswith('darwin'):
diff --git a/pypy/interpreter/pyparser/future.py b/pypy/interpreter/pyparser/future.py
--- a/pypy/interpreter/pyparser/future.py
+++ b/pypy/interpreter/pyparser/future.py
@@ -85,13 +85,17 @@
# permissive parsing of the given list of tokens; it relies on
# the real parsing done afterwards to give errors.
it.skip_newlines()
- it.skip_name("r") or it.skip_name("u") or it.skip_name("ru")
- if it.skip(pygram.tokens.STRING):
- it.skip_newlines()
- while (it.skip_name("from") and
+ docstring_possible = True
+ while True:
+ it.skip_name("r") or it.skip_name("u") or it.skip_name("ru")
+ if docstring_possible and it.skip(pygram.tokens.STRING):
+ it.skip_newlines()
+ docstring_possible = False
+ if not (it.skip_name("from") and
it.skip_name("__future__") and
it.skip_name("import")):
+ break
it.skip(pygram.tokens.LPAR) # optionally
# return in 'last_position' any line-column pair that points
# somewhere inside the last __future__ import statement
diff --git a/pypy/interpreter/pyparser/test/test_future.py b/pypy/interpreter/pyparser/test/test_future.py
--- a/pypy/interpreter/pyparser/test/test_future.py
+++ b/pypy/interpreter/pyparser/test/test_future.py
@@ -208,3 +208,13 @@
'from __future__ import with_statement;')
f = run(s, (2, 23))
assert f == fut.CO_FUTURE_DIVISION | fut.CO_FUTURE_WITH_STATEMENT
+
+def test_future_doc_future():
+ # for some reason people do this :-[
+ s = '''
+from __future__ import generators
+"Docstring"
+from __future__ import division
+ '''
+ f = run(s, (4, 24))
+ assert f == fut.CO_FUTURE_DIVISION | fut.CO_GENERATOR_ALLOWED
diff --git a/pypy/module/_continuation/test/test_stacklet.py b/pypy/module/_continuation/test/test_stacklet.py
--- a/pypy/module/_continuation/test/test_stacklet.py
+++ b/pypy/module/_continuation/test/test_stacklet.py
@@ -8,6 +8,35 @@
cls.w_translated = cls.space.wrap(
os.path.join(os.path.dirname(__file__),
'test_translated.py'))
+ cls.w_stack = cls.space.appexec([], """():
+ import sys
+ def stack(f=None):
+ '''
+ get the call-stack of the caller or the specified frame
+ '''
+ if f is None:
+ f = sys._getframe(1)
+ res = []
+ seen = set()
+ while f:
+ if f in seen:
+ # frame cycle
+ res.append('...')
+ break
+ if f.f_code.co_name == 'runtest':
+ # if we are running with -A, cut all the stack above
+ # the test function
+ break
+ seen.add(f)
+ res.append(f.f_code.co_name)
+ f = f.f_back
+ #print res
+ return res
+ return stack
+ """)
+ if cls.runappdirect:
+ # make sure that "self.stack" does not pass the self
+ cls.w_stack = staticmethod(cls.w_stack.im_func)
def test_new_empty(self):
from _continuation import continulet
@@ -290,66 +319,100 @@
def test_random_switching(self):
from _continuation import continulet
#
+ seen = []
+ #
def t1(c1):
- return c1.switch()
+ seen.append(3)
+ res = c1.switch()
+ seen.append(6)
+ return res
+ #
def s1(c1, n):
+ seen.append(2)
assert n == 123
c2 = t1(c1)
- return c1.switch('a') + 1
+ seen.append(7)
+ res = c1.switch('a') + 1
+ seen.append(10)
+ return res
#
def s2(c2, c1):
+ seen.append(5)
res = c1.switch(c2)
+ seen.append(8)
assert res == 'a'
- return c2.switch('b') + 2
+ res = c2.switch('b') + 2
+ seen.append(12)
+ return res
#
def f():
+ seen.append(1)
c1 = continulet(s1, 123)
c2 = continulet(s2, c1)
c1.switch()
+ seen.append(4)
res = c2.switch()
+ seen.append(9)
assert res == 'b'
res = c1.switch(1000)
+ seen.append(11)
assert res == 1001
- return c2.switch(2000)
+ res = c2.switch(2000)
+ seen.append(13)
+ return res
#
res = f()
assert res == 2002
+ assert seen == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
def test_f_back(self):
import sys
from _continuation import continulet
+ stack = self.stack
#
- def g(c):
+ def bar(c):
+ assert stack() == ['bar', 'foo', 'test_f_back']
c.switch(sys._getframe(0))
c.switch(sys._getframe(0).f_back)
c.switch(sys._getframe(1))
+ #
+ assert stack() == ['bar', 'foo', 'main', 'test_f_back']
c.switch(sys._getframe(1).f_back)
- assert sys._getframe(2) is f3.f_back
+ #
+ assert stack() == ['bar', 'foo', 'main2', 'test_f_back']
+ assert sys._getframe(2) is f3_foo.f_back
c.switch(sys._getframe(2))
- def f(c):
- g(c)
+ def foo(c):
+ bar(c)
#
- c = continulet(f)
- f1 = c.switch()
- assert f1.f_code.co_name == 'g'
- f2 = c.switch()
- assert f2.f_code.co_name == 'f'
- f3 = c.switch()
- assert f3 is f2
- assert f1.f_back is f3
+ assert stack() == ['test_f_back']
+ c = continulet(foo)
+ f1_bar = c.switch()
+ assert f1_bar.f_code.co_name == 'bar'
+ f2_foo = c.switch()
+ assert f2_foo.f_code.co_name == 'foo'
+ f3_foo = c.switch()
+ assert f3_foo is f2_foo
+ assert f1_bar.f_back is f3_foo
+ #
def main():
- f4 = c.switch()
- assert f4.f_code.co_name == 'main', repr(f4.f_code.co_name)
- assert f3.f_back is f1 # not running, so a loop
+ f4_main = c.switch()
+ assert f4_main.f_code.co_name == 'main'
+ assert f3_foo.f_back is f1_bar # not running, so a loop
+ assert stack() == ['main', 'test_f_back']
+ assert stack(f1_bar) == ['bar', 'foo', '...']
+ #
def main2():
- f5 = c.switch()
- assert f5.f_code.co_name == 'main2', repr(f5.f_code.co_name)
- assert f3.f_back is f1 # not running, so a loop
+ f5_main2 = c.switch()
+ assert f5_main2.f_code.co_name == 'main2'
+ assert f3_foo.f_back is f1_bar # not running, so a loop
+ assert stack(f1_bar) == ['bar', 'foo', '...']
+ #
main()
main2()
res = c.switch()
assert res is None
- assert f3.f_back is None
+ assert f3_foo.f_back is None
def test_traceback_is_complete(self):
import sys
diff --git a/pypy/module/_continuation/test/test_translated.py b/pypy/module/_continuation/test/test_translated.py
--- a/pypy/module/_continuation/test/test_translated.py
+++ b/pypy/module/_continuation/test/test_translated.py
@@ -5,6 +5,7 @@
py.test.skip("to run on top of a translated pypy-c")
import sys, random
+from rpython.tool.udir import udir
# ____________________________________________________________
@@ -92,6 +93,33 @@
from pypy.conftest import option
if not option.runappdirect:
py.test.skip("meant only for -A run")
+ cls.w_vmprof_file = cls.space.wrap(str(udir.join('profile.vmprof')))
+
+ def test_vmprof(self):
+ """
+ The point of this test is to check that we do NOT segfault. In
+ particular, we need to ensure that vmprof does not sample the stack in
+ the middle of a switch, else we read nonsense.
+ """
+ try:
+ import _vmprof
+ except ImportError:
+ py.test.skip("no _vmprof")
+ #
+ def switch_forever(c):
+ while True:
+ c.switch()
+ #
+ f = open(self.vmprof_file, 'w+b')
+ _vmprof.enable(f.fileno(), 1/250.0, False, False, False, False)
+ c = _continuation.continulet(switch_forever)
+ for i in range(10**7):
+ if i % 100000 == 0:
+ print i
+ c.switch()
+ _vmprof.disable()
+ f.close()
+
def _setup():
for _i in range(20):
diff --git a/pypy/module/_cppyy/__init__.py b/pypy/module/_cppyy/__init__.py
--- a/pypy/module/_cppyy/__init__.py
+++ b/pypy/module/_cppyy/__init__.py
@@ -7,7 +7,7 @@
interpleveldefs = {
'_resolve_name' : 'interp_cppyy.resolve_name',
'_scope_byname' : 'interp_cppyy.scope_byname',
- '_template_byname' : 'interp_cppyy.template_byname',
+ '_is_template' : 'interp_cppyy.is_template',
'_std_string_name' : 'interp_cppyy.std_string_name',
'_set_class_generator' : 'interp_cppyy.set_class_generator',
'_set_function_generator': 'interp_cppyy.set_function_generator',
@@ -15,7 +15,9 @@
'_get_nullptr' : 'interp_cppyy.get_nullptr',
'CPPClassBase' : 'interp_cppyy.W_CPPClass',
'addressof' : 'interp_cppyy.addressof',
+ '_bind_object' : 'interp_cppyy._bind_object',
'bind_object' : 'interp_cppyy.bind_object',
+ 'move' : 'interp_cppyy.move',
}
appleveldefs = {
diff --git a/pypy/module/_cppyy/capi/loadable_capi.py b/pypy/module/_cppyy/capi/loadable_capi.py
--- a/pypy/module/_cppyy/capi/loadable_capi.py
+++ b/pypy/module/_cppyy/capi/loadable_capi.py
@@ -217,7 +217,8 @@
'method_req_args' : ([c_scope, c_index], c_int),
'method_arg_type' : ([c_scope, c_index, c_int], c_ccharp),
'method_arg_default' : ([c_scope, c_index, c_int], c_ccharp),
- 'method_signature' : ([c_scope, c_index], c_ccharp),
+ 'method_signature' : ([c_scope, c_index, c_int], c_ccharp),
+ 'method_prototype' : ([c_scope, c_index, c_int], c_ccharp),
'method_is_template' : ([c_scope, c_index], c_int),
'method_num_template_args' : ([c_scope, c_index], c_int),
@@ -498,9 +499,12 @@
def c_method_arg_default(space, cppscope, index, arg_index):
args = [_ArgH(cppscope.handle), _ArgL(index), _ArgL(arg_index)]
return charp2str_free(space, call_capi(space, 'method_arg_default', args))
-def c_method_signature(space, cppscope, index):
- args = [_ArgH(cppscope.handle), _ArgL(index)]
+def c_method_signature(space, cppscope, index, show_formalargs=True):
+ args = [_ArgH(cppscope.handle), _ArgL(index), _ArgL(show_formalargs)]
return charp2str_free(space, call_capi(space, 'method_signature', args))
+def c_method_prototype(space, cppscope, index, show_formalargs=True):
+ args = [_ArgH(cppscope.handle), _ArgL(index), _ArgL(show_formalargs)]
+ return charp2str_free(space, call_capi(space, 'method_prototype', args))
def c_method_is_template(space, cppscope, index):
args = [_ArgH(cppscope.handle), _ArgL(index)]
diff --git a/pypy/module/_cppyy/converter.py b/pypy/module/_cppyy/converter.py
--- a/pypy/module/_cppyy/converter.py
+++ b/pypy/module/_cppyy/converter.py
@@ -4,7 +4,7 @@
from rpython.rtyper.lltypesystem import rffi, lltype
from rpython.rlib.rarithmetic import r_singlefloat, r_longfloat
-from rpython.rlib import rfloat
+from rpython.rlib import rfloat, rawrefcount
from pypy.module._rawffi.interp_rawffi import letter2tp
from pypy.module._rawffi.array import W_Array, W_ArrayInstance
@@ -21,9 +21,9 @@
# match for the qualified type.
-def get_rawobject(space, w_obj):
+def get_rawobject(space, w_obj, can_be_None=True):
from pypy.module._cppyy.interp_cppyy import W_CPPClass
- cppinstance = space.interp_w(W_CPPClass, w_obj, can_be_None=True)
+ cppinstance = space.interp_w(W_CPPClass, w_obj, can_be_None=can_be_None)
if cppinstance:
rawobject = cppinstance.get_rawobject()
assert lltype.typeOf(rawobject) == capi.C_OBJECT
@@ -48,17 +48,16 @@
return capi.C_NULL_OBJECT
def is_nullpointer_specialcase(space, w_obj):
- # 0, None, and nullptr may serve as "NULL", check for any of them
+ # 0 and nullptr may serve as "NULL"
# integer 0
try:
return space.int_w(w_obj) == 0
except Exception:
pass
- # None or nullptr
+ # C++-style nullptr
from pypy.module._cppyy import interp_cppyy
- return space.is_true(space.is_(w_obj, space.w_None)) or \
- space.is_true(space.is_(w_obj, interp_cppyy.get_nullptr(space)))
+ return space.is_true(space.is_(w_obj, interp_cppyy.get_nullptr(space)))
def get_rawbuffer(space, w_obj):
# raw buffer
@@ -74,7 +73,7 @@
return rffi.cast(rffi.VOIDP, space.uint_w(arr.getbuffer(space)))
except Exception:
pass
- # pre-defined NULL
+ # pre-defined nullptr
if is_nullpointer_specialcase(space, w_obj):
return rffi.cast(rffi.VOIDP, 0)
raise TypeError("not an addressable buffer")
@@ -392,6 +391,7 @@
_immutable_fields_ = ['typecode']
typecode = 'g'
+
class CStringConverter(TypeConverter):
def convert_argument(self, space, w_obj, address, call_local):
x = rffi.cast(rffi.LONGP, address)
@@ -408,18 +408,27 @@
def free_argument(self, space, arg, call_local):
lltype.free(rffi.cast(rffi.CCHARPP, arg)[0], flavor='raw')
+class CStringConverterWithSize(CStringConverter):
+ _immutable_fields_ = ['size']
+
+ def __init__(self, space, extra):
+ self.size = extra
+
+ def from_memory(self, space, w_obj, w_pycppclass, offset):
+ address = self._get_raw_address(space, w_obj, offset)
+ charpptr = rffi.cast(rffi.CCHARP, address)
+ strsize = self.size
+ if charpptr[self.size-1] == '\0':
+ strsize = self.size-1 # rffi will add \0 back
+ return space.newbytes(rffi.charpsize2str(charpptr, strsize))
+
class VoidPtrConverter(TypeConverter):
def _unwrap_object(self, space, w_obj):
try:
obj = get_rawbuffer(space, w_obj)
except TypeError:
- try:
- # TODO: accept a 'capsule' rather than naked int
- # (do accept int(0), though)
- obj = rffi.cast(rffi.VOIDP, space.uint_w(w_obj))
- except Exception:
- obj = rffi.cast(rffi.VOIDP, get_rawobject(space, w_obj))
+ obj = rffi.cast(rffi.VOIDP, get_rawobject(space, w_obj, False))
return obj
def cffi_type(self, space):
@@ -463,12 +472,12 @@
def convert_argument(self, space, w_obj, address, call_local):
x = rffi.cast(rffi.VOIDPP, address)
ba = rffi.cast(rffi.CCHARP, address)
- r = rffi.cast(rffi.VOIDPP, call_local)
try:
- r[0] = get_rawbuffer(space, w_obj)
+ x[0] = get_rawbuffer(space, w_obj)
except TypeError:
+ r = rffi.cast(rffi.VOIDPP, call_local)
r[0] = rffi.cast(rffi.VOIDP, get_rawobject(space, w_obj))
- x[0] = rffi.cast(rffi.VOIDP, call_local)
+ x[0] = rffi.cast(rffi.VOIDP, call_local)
ba[capi.c_function_arg_typeoffset(space)] = self.typecode
def finalize_call(self, space, w_obj, call_local):
@@ -495,9 +504,13 @@
def _unwrap_object(self, space, w_obj):
from pypy.module._cppyy.interp_cppyy import W_CPPClass
if isinstance(w_obj, W_CPPClass):
- if capi.c_is_subtype(space, w_obj.cppclass, self.clsdecl):
+ from pypy.module._cppyy.interp_cppyy import INSTANCE_FLAGS_IS_R_VALUE
+ if w_obj.flags & INSTANCE_FLAGS_IS_R_VALUE:
+ # reject moves as all are explicit
+ raise ValueError("lvalue expected")
+ if capi.c_is_subtype(space, w_obj.clsdecl, self.clsdecl):
rawobject = w_obj.get_rawobject()
- offset = capi.c_base_offset(space, w_obj.cppclass, self.clsdecl, rawobject, 1)
+ offset = capi.c_base_offset(space, w_obj.clsdecl, self.clsdecl, rawobject, 1)
obj_address = capi.direct_ptradd(rawobject, offset)
return rffi.cast(capi.C_OBJECT, obj_address)
raise oefmt(space.w_TypeError,
@@ -518,6 +531,17 @@
x = rffi.cast(rffi.VOIDPP, address)
x[0] = rffi.cast(rffi.VOIDP, self._unwrap_object(space, w_obj))
+class InstanceMoveConverter(InstanceRefConverter):
+ def _unwrap_object(self, space, w_obj):
+ # moving is same as by-ref, but have to check that move is allowed
+ from pypy.module._cppyy.interp_cppyy import W_CPPClass, INSTANCE_FLAGS_IS_R_VALUE
+ if isinstance(w_obj, W_CPPClass):
+ if w_obj.flags & INSTANCE_FLAGS_IS_R_VALUE:
+ w_obj.flags &= ~INSTANCE_FLAGS_IS_R_VALUE
+ return InstanceRefConverter._unwrap_object(self, space, w_obj)
+ raise oefmt(space.w_ValueError, "object is not an rvalue")
+
+
class InstanceConverter(InstanceRefConverter):
def convert_argument_libffi(self, space, w_obj, address, call_local):
@@ -527,7 +551,7 @@
def from_memory(self, space, w_obj, w_pycppclass, offset):
address = rffi.cast(capi.C_OBJECT, self._get_raw_address(space, w_obj, offset))
from pypy.module._cppyy import interp_cppyy
- return interp_cppyy.wrap_cppobject(space, address, self.clsdecl, do_cast=False)
+ return interp_cppyy.wrap_cppinstance(space, address, self.clsdecl, do_cast=False)
def to_memory(self, space, w_obj, w_value, offset):
self._is_abstract(space)
@@ -548,7 +572,7 @@
def from_memory(self, space, w_obj, w_pycppclass, offset):
address = rffi.cast(capi.C_OBJECT, self._get_raw_address(space, w_obj, offset))
from pypy.module._cppyy import interp_cppyy
- return interp_cppyy.wrap_cppobject(space, address, self.clsdecl, do_cast=False)
+ return interp_cppyy.wrap_cppinstance(space, address, self.clsdecl, do_cast=False)
def to_memory(self, space, w_obj, w_value, offset):
address = rffi.cast(rffi.VOIDPP, self._get_raw_address(space, w_obj, offset))
@@ -582,8 +606,8 @@
def from_memory(self, space, w_obj, w_pycppclass, offset):
address = rffi.cast(capi.C_OBJECT, self._get_raw_address(space, w_obj, offset))
from pypy.module._cppyy import interp_cppyy
- return interp_cppyy.wrap_cppobject(space, address, self.clsdecl,
- do_cast=False, is_ref=True)
+ return interp_cppyy.wrap_cppinstance(
+ space, address, self.clsdecl, do_cast=False, is_ref=True)
class StdStringConverter(InstanceConverter):
@@ -606,7 +630,7 @@
assign = self.clsdecl.get_overload("__assign__")
from pypy.module._cppyy import interp_cppyy
assign.call(
- interp_cppyy.wrap_cppobject(space, address, self.clsdecl, do_cast=False), [w_value])
+ interp_cppyy.wrap_cppinstance(space, address, self.clsdecl, do_cast=False), [w_value])
except Exception:
InstanceConverter.to_memory(self, space, w_obj, w_value, offset)
@@ -672,7 +696,7 @@
_converters = {} # builtin and custom types
_a_converters = {} # array and ptr versions of above
-def get_converter(space, name, default):
+def get_converter(space, _name, default):
# The matching of the name to a converter should follow:
# 1) full, exact match
# 1a) const-removed match
@@ -680,9 +704,9 @@
# 3) accept ref as pointer (for the stubs, const& can be
# by value, but that does not work for the ffi path)
# 4) generalized cases (covers basically all user classes)
- # 5) void converter, which fails on use
+ # 5) void* or void converter (which fails on use)
- name = capi.c_resolve_name(space, name)
+ name = capi.c_resolve_name(space, _name)
# 1) full, exact match
try:
@@ -701,7 +725,7 @@
clean_name = capi.c_resolve_name(space, helper.clean_type(name))
try:
# array_index may be negative to indicate no size or no size found
- array_size = helper.array_size(name)
+ array_size = helper.array_size(_name) # uses original arg
return _a_converters[clean_name+compound](space, array_size)
except KeyError:
pass
@@ -719,6 +743,8 @@
return InstancePtrConverter(space, clsdecl)
elif compound == "&":
return InstanceRefConverter(space, clsdecl)
+ elif compound == "&&":
+ return InstanceMoveConverter(space, clsdecl)
elif compound == "**":
return InstancePtrPtrConverter(space, clsdecl)
elif compound == "":
@@ -726,11 +752,13 @@
elif capi.c_is_enum(space, clean_name):
return _converters['unsigned'](space, default)
- # 5) void converter, which fails on use
- #
+ # 5) void* or void converter (which fails on use)
+ if 0 <= compound.find('*'):
+ return VoidPtrConverter(space, default) # "user knows best"
+
# return a void converter here, so that the class can be build even
- # when some types are unknown; this overload will simply fail on use
- return VoidConverter(space, name)
+ # when some types are unknown
+ return VoidConverter(space, name) # fails on use
_converters["bool"] = BoolConverter
@@ -847,6 +875,10 @@
for name in names:
_a_converters[name+'[]'] = ArrayConverter
_a_converters[name+'*'] = PtrConverter
+
+ # special case, const char* w/ size and w/o '\0'
+ _a_converters["const char[]"] = CStringConverterWithSize
+
_build_array_converters()
# add another set of aliased names
diff --git a/pypy/module/_cppyy/executor.py b/pypy/module/_cppyy/executor.py
--- a/pypy/module/_cppyy/executor.py
+++ b/pypy/module/_cppyy/executor.py
@@ -159,7 +159,7 @@
from pypy.module._cppyy import interp_cppyy
long_result = capi.c_call_l(space, cppmethod, cppthis, num_args, args)
ptr_result = rffi.cast(capi.C_OBJECT, long_result)
- pyres = interp_cppyy.wrap_cppobject(space, ptr_result, self.cppclass)
+ pyres = interp_cppyy.wrap_cppinstance(space, ptr_result, self.cppclass)
return pyres
def execute_libffi(self, space, cif_descr, funcaddr, buffer):
@@ -167,7 +167,7 @@
result = rffi.ptradd(buffer, cif_descr.exchange_result)
from pypy.module._cppyy import interp_cppyy
ptr_result = rffi.cast(capi.C_OBJECT, rffi.cast(rffi.VOIDPP, result)[0])
- return interp_cppyy.wrap_cppobject(space, ptr_result, self.cppclass)
+ return interp_cppyy.wrap_cppinstance(space, ptr_result, self.cppclass)
class InstancePtrPtrExecutor(InstancePtrExecutor):
@@ -176,7 +176,7 @@
voidp_result = capi.c_call_r(space, cppmethod, cppthis, num_args, args)
ref_address = rffi.cast(rffi.VOIDPP, voidp_result)
ptr_result = rffi.cast(capi.C_OBJECT, ref_address[0])
- return interp_cppyy.wrap_cppobject(space, ptr_result, self.cppclass)
+ return interp_cppyy.wrap_cppinstance(space, ptr_result, self.cppclass)
def execute_libffi(self, space, cif_descr, funcaddr, buffer):
from pypy.module._cppyy.interp_cppyy import FastCallNotPossible
@@ -188,8 +188,8 @@
from pypy.module._cppyy import interp_cppyy
long_result = capi.c_call_o(space, cppmethod, cppthis, num_args, args, self.cppclass)
ptr_result = rffi.cast(capi.C_OBJECT, long_result)
- return interp_cppyy.wrap_cppobject(space, ptr_result, self.cppclass,
- do_cast=False, python_owns=True, fresh=True)
+ return interp_cppyy.wrap_cppinstance(space, ptr_result, self.cppclass,
+ do_cast=False, python_owns=True, fresh=True)
def execute_libffi(self, space, cif_descr, funcaddr, buffer):
from pypy.module._cppyy.interp_cppyy import FastCallNotPossible
diff --git a/pypy/module/_cppyy/include/capi.h b/pypy/module/_cppyy/include/capi.h
--- a/pypy/module/_cppyy/include/capi.h
+++ b/pypy/module/_cppyy/include/capi.h
@@ -19,14 +19,15 @@
RPY_EXTERN
int cppyy_num_scopes(cppyy_scope_t parent);
RPY_EXTERN
- char* cppyy_scope_name(cppyy_scope_t parent, int iscope);
-
+ char* cppyy_scope_name(cppyy_scope_t parent, cppyy_index_t iscope);
RPY_EXTERN
char* cppyy_resolve_name(const char* cppitem_name);
RPY_EXTERN
cppyy_scope_t cppyy_get_scope(const char* scope_name);
RPY_EXTERN
cppyy_type_t cppyy_actual_class(cppyy_type_t klass, cppyy_object_t obj);
+ RPY_EXTERN
+ size_t cppyy_size_of(cppyy_type_t klass);
/* memory management ------------------------------------------------------ */
RPY_EXTERN
@@ -120,6 +121,8 @@
RPY_EXTERN
char* cppyy_method_name(cppyy_scope_t scope, cppyy_index_t idx);
RPY_EXTERN
+ char* cppyy_method_mangled_name(cppyy_scope_t scope, cppyy_index_t idx);
+ RPY_EXTERN
char* cppyy_method_result_type(cppyy_scope_t scope, cppyy_index_t idx);
RPY_EXTERN
int cppyy_method_num_args(cppyy_scope_t scope, cppyy_index_t idx);
@@ -130,7 +133,9 @@
RPY_EXTERN
char* cppyy_method_arg_default(cppyy_scope_t scope, cppyy_index_t idx, int arg_index);
RPY_EXTERN
- char* cppyy_method_signature(cppyy_scope_t scope, cppyy_index_t idx);
+ char* cppyy_method_signature(cppyy_scope_t scope, cppyy_index_t idx, int show_formalargs);
+ RPY_EXTERN
+ char* cppyy_method_prototype(cppyy_scope_t scope, cppyy_index_t idx, int show_formalargs);
RPY_EXTERN
int cppyy_method_is_template(cppyy_scope_t scope, cppyy_index_t idx);
@@ -147,8 +152,12 @@
/* method properties ------------------------------------------------------ */
RPY_EXTERN
+ int cppyy_is_publicmethod(cppyy_type_t type, cppyy_index_t idx);
+ RPY_EXTERN
int cppyy_is_constructor(cppyy_type_t type, cppyy_index_t idx);
RPY_EXTERN
+ int cppyy_is_destructor(cppyy_type_t type, cppyy_index_t idx);
+ RPY_EXTERN
int cppyy_is_staticmethod(cppyy_type_t type, cppyy_index_t idx);
/* data member reflection information ------------------------------------- */
diff --git a/pypy/module/_cppyy/interp_cppyy.py b/pypy/module/_cppyy/interp_cppyy.py
--- a/pypy/module/_cppyy/interp_cppyy.py
+++ b/pypy/module/_cppyy/interp_cppyy.py
@@ -2,7 +2,7 @@
from pypy.interpreter.error import OperationError, oefmt
from pypy.interpreter.gateway import interp2app, unwrap_spec
-from pypy.interpreter.typedef import TypeDef, GetSetProperty, interp_attrproperty, interp_attrproperty_w
+from pypy.interpreter.typedef import TypeDef, GetSetProperty, interp_attrproperty
from pypy.interpreter.baseobjspace import W_Root
from rpython.rtyper.lltypesystem import rffi, lltype, llmemory
@@ -15,6 +15,10 @@
from pypy.module._cppyy import converter, executor, ffitypes, helper
+INSTANCE_FLAGS_PYTHON_OWNS = 0x0001
+INSTANCE_FLAGS_IS_REF = 0x0002
+INSTANCE_FLAGS_IS_R_VALUE = 0x0004
+
class FastCallNotPossible(Exception):
pass
@@ -33,16 +37,21 @@
class State(object):
def __init__(self, space):
+ # final scoped name -> opaque handle
self.cppscope_cache = {
- "void" : W_CPPClassDecl(space, "void", capi.C_NULL_TYPE) }
+ 'void' : W_CPPClassDecl(space, capi.C_NULL_TYPE, 'void') }
+ # opaque handle -> app-level python class
+ self.cppclass_registry = {}
+ # app-level class generator callback
+ self.w_clgen_callback = None
+ # app-level function generator callback (currently not used)
+ self.w_fngen_callback = None
+ # C++11's nullptr
self.w_nullptr = None
- self.cpptemplate_cache = {}
- self.cppclass_registry = {}
- self.w_clgen_callback = None
- self.w_fngen_callback = None
def get_nullptr(space):
- if hasattr(space, "fake"):
+ # construct a unique address that compares to NULL, serves as nullptr
+ if hasattr(space, 'fake'):
raise NotImplementedError
state = space.fromcache(State)
if state.w_nullptr is None:
@@ -58,52 +67,48 @@
state.w_nullptr = nullarr
return state.w_nullptr
- at unwrap_spec(name='text')
-def resolve_name(space, name):
- return space.newtext(capi.c_resolve_name(space, name))
+ at unwrap_spec(scoped_name='text')
+def resolve_name(space, scoped_name):
+ return space.newtext(capi.c_resolve_name(space, scoped_name))
- at unwrap_spec(name='text')
-def scope_byname(space, name):
- true_name = capi.c_resolve_name(space, name)
+# memoized lookup of handles by final, scoped, name of classes/namespaces
+ at unwrap_spec(final_scoped_name='text')
+def scope_byname(space, final_scoped_name):
state = space.fromcache(State)
try:
- return state.cppscope_cache[true_name]
+ return state.cppscope_cache[final_scoped_name]
except KeyError:
pass
- opaque_handle = capi.c_get_scope_opaque(space, true_name)
+ opaque_handle = capi.c_get_scope_opaque(space, final_scoped_name)
assert lltype.typeOf(opaque_handle) == capi.C_SCOPE
if opaque_handle:
- final_name = capi.c_final_name(space, opaque_handle)
- if capi.c_is_namespace(space, opaque_handle):
- cppscope = W_CPPNamespaceDecl(space, final_name, opaque_handle)
- elif capi.c_has_complex_hierarchy(space, opaque_handle):
- cppscope = W_CPPComplexClassDecl(space, final_name, opaque_handle)
+ isns = capi.c_is_namespace(space, opaque_handle)
+ if isns:
+ cppscope = W_CPPNamespaceDecl(space, opaque_handle, final_scoped_name)
else:
- cppscope = W_CPPClassDecl(space, final_name, opaque_handle)
- state.cppscope_cache[name] = cppscope
+ if capi.c_has_complex_hierarchy(space, opaque_handle):
+ cppscope = W_CPPComplexClassDecl(space, opaque_handle, final_scoped_name)
+ else:
+ cppscope = W_CPPClassDecl(space, opaque_handle, final_scoped_name)
- cppscope._build_methods()
- cppscope._find_datamembers()
+ # store in the cache to prevent recursion
+ state.cppscope_cache[final_scoped_name] = cppscope
+
+ if not isns:
+ # build methods/data; TODO: also defer this for classes (a functional __dir__
+ # and instrospection for help() is enough and allows more lazy loading)
+ cppscope._build_methods()
+ cppscope._find_datamembers()
+
return cppscope
return None
- at unwrap_spec(name='text')
-def template_byname(space, name):
- state = space.fromcache(State)
- try:
- return state.cpptemplate_cache[name]
- except KeyError:
- pass
-
- if capi.c_is_template(space, name):
- cpptemplate = W_CPPTemplateType(space, name)
- state.cpptemplate_cache[name] = cpptemplate
- return cpptemplate
-
- return None
+ at unwrap_spec(final_scoped_name='text')
+def is_template(space, final_scoped_name):
+ return space.newbool(capi.c_is_template(space, final_scoped_name))
def std_string_name(space):
return space.newtext(capi.std_string_name)
@@ -189,8 +194,13 @@
# check number of given arguments against required (== total - defaults)
args_expected = len(self.arg_defs)
args_given = len(args_w)
- if args_expected < args_given or args_given < self.args_required:
- raise oefmt(self.space.w_TypeError, "wrong number of arguments")
+
+ if args_given < self.args_required:
+ raise oefmt(self.space.w_TypeError,
+ "takes at least %d arguments (%d given)", self.args_required, args_given)
+ elif args_expected < args_given:
+ raise oefmt(self.space.w_TypeError,
+ "takes at most %d arguments (%d given)", args_expected, args_given)
# initial setup of converters, executors, and libffi (if available)
if self.converters is None:
@@ -376,8 +386,11 @@
conv.free_argument(self.space, rffi.cast(capi.C_OBJECT, arg_i), loc_i)
capi.c_deallocate_function_args(self.space, args)
- def signature(self):
- return capi.c_method_signature(self.space, self.scope, self.index)
+ def signature(self, show_formalargs=True):
+ return capi.c_method_signature(self.space, self.scope, self.index, show_formalargs)
+
+ def prototype(self, show_formalargs=True):
+ return capi.c_method_prototype(self.space, self.scope, self.index, show_formalargs)
def priority(self):
total_arg_priority = 0
@@ -391,7 +404,7 @@
lltype.free(self.cif_descr, flavor='raw')
def __repr__(self):
- return "CPPMethod: %s" % self.signature()
+ return "CPPMethod: %s" % self.prototype()
def _freeze_(self):
assert 0, "you should never have a pre-built instance of this!"
@@ -407,7 +420,7 @@
return capi.C_NULL_OBJECT
def __repr__(self):
- return "CPPFunction: %s" % self.signature()
+ return "CPPFunction: %s" % self.prototype()
class CPPTemplatedCall(CPPMethod):
@@ -440,7 +453,7 @@
return CPPMethod.call(self, cppthis, args_w)
def __repr__(self):
- return "CPPTemplatedCall: %s" % self.signature()
+ return "CPPTemplatedCall: %s" % self.prototype()
class CPPConstructor(CPPMethod):
@@ -462,7 +475,7 @@
return CPPMethod.call(self, cppthis, args_w)
def __repr__(self):
- return "CPPConstructor: %s" % self.signature()
+ return "CPPConstructor: %s" % self.prototype()
class CPPSetItem(CPPMethod):
@@ -549,12 +562,12 @@
w_exc_type = e.w_type
elif all_same_type and not e.match(self.space, w_exc_type):
all_same_type = False
- errmsg += '\n '+cppyyfunc.signature()+' =>\n'
+ errmsg += '\n '+cppyyfunc.prototype()+' =>\n'
errmsg += ' '+e.errorstr(self.space)
except Exception as e:
# can not special case this for non-overloaded functions as we anyway need an
# OperationError error down from here
- errmsg += '\n '+cppyyfunc.signature()+' =>\n'
+ errmsg += '\n '+cppyyfunc.prototype()+' =>\n'
errmsg += ' Exception: '+str(e)
if all_same_type and w_exc_type is not None:
@@ -562,20 +575,20 @@
else:
raise OperationError(self.space.w_TypeError, self.space.newtext(errmsg))
- def signature(self):
- sig = self.functions[0].signature()
+ def prototype(self):
+ sig = self.functions[0].prototype()
for i in range(1, len(self.functions)):
- sig += '\n'+self.functions[i].signature()
+ sig += '\n'+self.functions[i].prototype()
return self.space.newtext(sig)
def __repr__(self):
- return "W_CPPOverload(%s)" % [f.signature() for f in self.functions]
+ return "W_CPPOverload(%s)" % [f.prototype() for f in self.functions]
W_CPPOverload.typedef = TypeDef(
'CPPOverload',
is_static = interp2app(W_CPPOverload.is_static),
call = interp2app(W_CPPOverload.call),
- signature = interp2app(W_CPPOverload.signature),
+ prototype = interp2app(W_CPPOverload.prototype),
)
@@ -591,24 +604,40 @@
@jit.unroll_safe
@unwrap_spec(args_w='args_w')
def call(self, w_cppinstance, args_w):
+ # TODO: factor out the following:
+ if capi.c_is_abstract(self.space, self.scope.handle):
+ raise oefmt(self.space.w_TypeError,
+ "cannot instantiate abstract class '%s'",
+ self.scope.name)
w_result = W_CPPOverload.call(self, w_cppinstance, args_w)
newthis = rffi.cast(capi.C_OBJECT, self.space.uint_w(w_result))
cppinstance = self.space.interp_w(W_CPPClass, w_cppinstance, can_be_None=True)
if cppinstance is not None:
cppinstance._rawobject = newthis
memory_regulator.register(cppinstance)
- return w_cppinstance
- return wrap_cppobject(self.space, newthis, self.functions[0].scope,
- do_cast=False, python_owns=True, fresh=True)
def __repr__(self):
- return "W_CPPConstructorOverload(%s)" % [f.signature() for f in self.functions]
+ return "W_CPPConstructorOverload(%s)" % [f.prototype() for f in self.functions]
W_CPPConstructorOverload.typedef = TypeDef(
'CPPConstructorOverload',
is_static = interp2app(W_CPPConstructorOverload.is_static),
call = interp2app(W_CPPConstructorOverload.call),
- signature = interp2app(W_CPPOverload.signature),
+ prototype = interp2app(W_CPPConstructorOverload.prototype),
+)
+
+
+class W_CPPTemplateOverload(W_CPPOverload):
+ @unwrap_spec(args_w='args_w')
+ def __getitem__(self, args_w):
+ pass
+
+ def __repr__(self):
+ return "W_CPPTemplateOverload(%s)" % [f.prototype() for f in self.functions]
+
+W_CPPTemplateOverload.typedef = TypeDef(
+ 'CPPTemplateOverload',
+ __getitem__ = interp2app(W_CPPTemplateOverload.call),
)
@@ -622,6 +651,9 @@
def __call__(self, args_w):
return self.method.bound_call(self.cppthis, args_w)
+ def __repr__(self):
+ return "W_CPPBoundMethod(%s)" % [f.prototype() for f in self.functions]
+
W_CPPBoundMethod.typedef = TypeDef(
'CPPBoundMethod',
__call__ = interp2app(W_CPPBoundMethod.__call__),
@@ -643,8 +675,8 @@
def _get_offset(self, cppinstance):
if cppinstance:
- assert lltype.typeOf(cppinstance.cppclass.handle) == lltype.typeOf(self.scope.handle)
- offset = self.offset + cppinstance.cppclass.get_base_offset(cppinstance, self.scope)
+ assert lltype.typeOf(cppinstance.clsdecl.handle) == lltype.typeOf(self.scope.handle)
+ offset = self.offset + cppinstance.clsdecl.get_base_offset(cppinstance, self.scope)
else:
offset = self.offset
return offset
@@ -652,7 +684,7 @@
def get(self, w_cppinstance, w_pycppclass):
cppinstance = self.space.interp_w(W_CPPClass, w_cppinstance, can_be_None=True)
if not cppinstance:
- raise oefmt(self.space.w_ReferenceError,
+ raise oefmt(self.space.w_AttributeError,
"attribute access requires an instance")
offset = self._get_offset(cppinstance)
return self.converter.from_memory(self.space, w_cppinstance, w_pycppclass, offset)
@@ -660,7 +692,7 @@
def set(self, w_cppinstance, w_value):
cppinstance = self.space.interp_w(W_CPPClass, w_cppinstance, can_be_None=True)
if not cppinstance:
- raise oefmt(self.space.w_ReferenceError,
+ raise oefmt(self.space.w_AttributeError,
"attribute access requires an instance")
offset = self._get_offset(cppinstance)
self.converter.to_memory(self.space, w_cppinstance, w_value, offset)
@@ -705,12 +737,12 @@
return space.w_False
class W_CPPScopeDecl(W_Root):
- _attrs_ = ['space', 'name', 'handle', 'methods', 'datamembers']
+ _attrs_ = ['space', 'handle', 'name', 'methods', 'datamembers']
_immutable_fields_ = ['handle', 'name']
- def __init__(self, space, name, opaque_handle):
+ def __init__(self, space, opaque_handle, final_scoped_name):
self.space = space
- self.name = name
+ self.name = final_scoped_name
assert lltype.typeOf(opaque_handle) == capi.C_SCOPE
self.handle = opaque_handle
self.methods = {}
@@ -753,7 +785,7 @@
overload = self.get_overload(name)
sig = '(%s)' % signature
for f in overload.functions:
- if 0 < f.signature().find(sig):
+ if f.signature(False) == sig:
return W_CPPOverload(self.space, self, [f])
raise oefmt(self.space.w_LookupError, "no overload matches signature")
@@ -769,6 +801,9 @@
# classes for inheritance. Both are python classes, though, and refactoring
# may be in order at some point.
class W_CPPNamespaceDecl(W_CPPScopeDecl):
+ _attrs_ = ['space', 'handle', 'name', 'methods', 'datamembers']
+ _immutable_fields_ = ['handle', 'name']
+
def _make_cppfunction(self, pyname, index):
num_args = capi.c_method_num_args(self.space, self, index)
args_required = capi.c_method_req_args(self.space, self, index)
@@ -779,9 +814,6 @@
arg_defs.append((arg_type, arg_dflt))
return CPPFunction(self.space, self, index, arg_defs, args_required)
- def _build_methods(self):
- pass # force lazy lookups in namespaces
-
def _make_datamember(self, dm_name, dm_idx):
type_name = capi.c_datamember_type(self.space, self, dm_idx)
offset = capi.c_datamember_offset(self.space, self, dm_idx)
@@ -791,9 +823,6 @@
self.datamembers[dm_name] = datamember
return datamember
- def _find_datamembers(self):
- pass # force lazy lookups in namespaces
-
def find_overload(self, meth_name):
indices = capi.c_method_indices_from_name(self.space, self, meth_name)
if not indices:
@@ -855,18 +884,21 @@
class W_CPPClassDecl(W_CPPScopeDecl):
- _attrs_ = ['space', 'name', 'handle', 'methods', 'datamembers']
- _immutable_fields_ = ['handle', 'constructor', 'methods[*]', 'datamembers[*]']
+ _attrs_ = ['space', 'handle', 'name', 'methods', 'datamembers']
+ _immutable_fields_ = ['handle', 'name', 'methods[*]', 'datamembers[*]']
def _build_methods(self):
assert len(self.methods) == 0
methods_temp = {}
for i in range(capi.c_num_methods(self.space, self)):
idx = capi.c_method_index_at(self.space, self, i)
- pyname = helper.map_operator_name(self.space,
- capi.c_method_name(self.space, self, idx),
- capi.c_method_num_args(self.space, self, idx),
- capi.c_method_result_type(self.space, self, idx))
+ if capi.c_is_constructor(self.space, self, idx):
+ pyname = '__init__'
+ else:
+ pyname = helper.map_operator_name(self.space,
+ capi.c_method_name(self.space, self, idx),
+ capi.c_method_num_args(self.space, self, idx),
+ capi.c_method_result_type(self.space, self, idx))
cppmethod = self._make_cppfunction(pyname, idx)
methods_temp.setdefault(pyname, []).append(cppmethod)
# the following covers the case where the only kind of operator[](idx)
@@ -883,7 +915,7 @@
# create the overload methods from the method sets
for pyname, methods in methods_temp.iteritems():
CPPMethodSort(methods).sort()
- if pyname == self.name:
+ if pyname == '__init__':
overload = W_CPPConstructorOverload(self.space, self, methods[:])
else:
overload = W_CPPOverload(self.space, self, methods[:])
@@ -934,11 +966,11 @@
raise self.missing_attribute_error(name)
def get_base_offset(self, cppinstance, calling_scope):
- assert self == cppinstance.cppclass
+ assert self == cppinstance.clsdecl
return 0
def get_cppthis(self, cppinstance, calling_scope):
- assert self == cppinstance.cppclass
+ assert self == cppinstance.clsdecl
return cppinstance.get_rawobject()
def is_namespace(self):
@@ -973,13 +1005,13 @@
class W_CPPComplexClassDecl(W_CPPClassDecl):
def get_base_offset(self, cppinstance, calling_scope):
- assert self == cppinstance.cppclass
+ assert self == cppinstance.clsdecl
offset = capi.c_base_offset(self.space,
self, calling_scope, cppinstance.get_rawobject(), 1)
return offset
def get_cppthis(self, cppinstance, calling_scope):
- assert self == cppinstance.cppclass
+ assert self == cppinstance.clsdecl
offset = self.get_base_offset(cppinstance, calling_scope)
return capi.direct_ptradd(cppinstance.get_rawobject(), offset)
@@ -997,70 +1029,56 @@
W_CPPComplexClassDecl.typedef.acceptable_as_base_class = False
-class W_CPPTemplateType(W_Root):
- _attrs_ = ['space', 'name']
- _immutable_fields = ['name']
-
- def __init__(self, space, name):
- self.space = space
- self.name = name
-
- @unwrap_spec(args_w='args_w')
- def __call__(self, args_w):
- # TODO: this is broken but unused (see pythonify.py)
- fullname = "".join([self.name, '<', self.space.text_w(args_w[0]), '>'])
- return scope_byname(self.space, fullname)
-
-W_CPPTemplateType.typedef = TypeDef(
- 'CPPTemplateType',
- __call__ = interp2app(W_CPPTemplateType.__call__),
-)
-W_CPPTemplateType.typedef.acceptable_as_base_class = False
-
-
class W_CPPClass(W_Root):
- _attrs_ = ['space', 'cppclass', '_rawobject', 'isref', 'python_owns',
+ _attrs_ = ['space', 'clsdecl', '_rawobject', 'flags',
'finalizer_registered']
- _immutable_fields_ = ["cppclass", "isref"]
+ _immutable_fields_ = ['clsdecl']
finalizer_registered = False
- def __init__(self, space, cppclass, rawobject, isref, python_owns):
+ def __init__(self, space, decl, rawobject, isref, python_owns):
self.space = space
- self.cppclass = cppclass
+ self.clsdecl = decl
assert lltype.typeOf(rawobject) == capi.C_OBJECT
assert not isref or rawobject
self._rawobject = rawobject
assert not isref or not python_owns
- self.isref = isref
- self.python_owns = python_owns
- self._opt_register_finalizer()
+ self.flags = 0
+ if isref:
+ self.flags |= INSTANCE_FLAGS_IS_REF
+ if python_owns:
+ self.flags |= INSTANCE_FLAGS_PYTHON_OWNS
+ self._opt_register_finalizer()
def _opt_register_finalizer(self):
- if self.python_owns and not self.finalizer_registered \
- and not hasattr(self.space, "fake"):
+ if not self.finalizer_registered and not hasattr(self.space, "fake"):
+ assert self.flags & INSTANCE_FLAGS_PYTHON_OWNS
self.register_finalizer(self.space)
self.finalizer_registered = True
def _nullcheck(self):
- if not self._rawobject or (self.isref and not self.get_rawobject()):
+ if not self._rawobject or \
+ ((self.flags & INSTANCE_FLAGS_IS_REF) and not self.get_rawobject()):
raise oefmt(self.space.w_ReferenceError,
"trying to access a NULL pointer")
# allow user to determine ownership rules on a per object level
def fget_python_owns(self, space):
- return space.newbool(self.python_owns)
+ return space.newbool(bool(self.flags & INSTANCE_FLAGS_PYTHON_OWNS))
@unwrap_spec(value=bool)
def fset_python_owns(self, space, value):
- self.python_owns = space.is_true(value)
- self._opt_register_finalizer()
+ if space.is_true(value):
+ self.flags |= INSTANCE_FLAGS_PYTHON_OWNS
+ self._opt_register_finalizer()
+ else:
+ self.flags &= ~INSTANCE_FLAGS_PYTHON_OWNS
def get_cppthis(self, calling_scope):
- return self.cppclass.get_cppthis(self, calling_scope)
+ return self.clsdecl.get_cppthis(self, calling_scope)
def get_rawobject(self):
- if not self.isref:
+ if not (self.flags & INSTANCE_FLAGS_IS_REF):
return self._rawobject
else:
ptrptr = rffi.cast(rffi.VOIDPP, self._rawobject)
@@ -1078,12 +1096,9 @@
return None
def instance__init__(self, args_w):
- if capi.c_is_abstract(self.space, self.cppclass.handle):
- raise oefmt(self.space.w_TypeError,
- "cannot instantiate abstract class '%s'",
- self.cppclass.name)
- constructor_overload = self.cppclass.get_overload(self.cppclass.name)
- constructor_overload.call(self, args_w)
+ raise oefmt(self.space.w_TypeError,
+ "cannot instantiate abstract class '%s'",
+ self.clsdecl.name)
def instance__eq__(self, w_other):
# special case: if other is None, compare pointer-style
@@ -1099,7 +1114,7 @@
for name in ["", "__gnu_cxx", "__1"]:
nss = scope_byname(self.space, name)
meth_idx = capi.c_get_global_operator(
- self.space, nss, self.cppclass, other.cppclass, "operator==")
+ self.space, nss, self.clsdecl, other.clsdecl, "operator==")
if meth_idx != -1:
f = nss._make_cppfunction("operator==", meth_idx)
ol = W_CPPOverload(self.space, nss, [f])
@@ -1118,14 +1133,15 @@
# fallback 2: direct pointer comparison (the class comparison is needed since
# the first data member in a struct and the struct have the same address)
other = self.space.interp_w(W_CPPClass, w_other, can_be_None=False) # TODO: factor out
- iseq = (self._rawobject == other._rawobject) and (self.cppclass == other.cppclass)
+ iseq = (self._rawobject == other._rawobject) and (self.clsdecl == other.clsdecl)
return self.space.newbool(iseq)
def instance__ne__(self, w_other):
return self.space.not_(self.instance__eq__(w_other))
def instance__nonzero__(self):
- if not self._rawobject or (self.isref and not self.get_rawobject()):
+ if not self._rawobject or \
+ ((self.flags & INSTANCE_FLAGS_IS_REF) and not self.get_rawobject()):
return self.space.w_False
return self.space.w_True
@@ -1134,36 +1150,35 @@
if w_as_builtin is not None:
return self.space.len(w_as_builtin)
raise oefmt(self.space.w_TypeError,
- "'%s' has no length", self.cppclass.name)
+ "'%s' has no length", self.clsdecl.name)
def instance__cmp__(self, w_other):
w_as_builtin = self._get_as_builtin()
if w_as_builtin is not None:
return self.space.cmp(w_as_builtin, w_other)
raise oefmt(self.space.w_AttributeError,
- "'%s' has no attribute __cmp__", self.cppclass.name)
+ "'%s' has no attribute __cmp__", self.clsdecl.name)
def instance__repr__(self):
w_as_builtin = self._get_as_builtin()
if w_as_builtin is not None:
return self.space.repr(w_as_builtin)
return self.space.newtext("<%s object at 0x%x>" %
- (self.cppclass.name, rffi.cast(rffi.ULONG, self.get_rawobject())))
+ (self.clsdecl.name, rffi.cast(rffi.ULONG, self.get_rawobject())))
def destruct(self):
- if self._rawobject and not self.isref:
+ if self._rawobject and not (self.flags & INSTANCE_FLAGS_IS_REF):
memory_regulator.unregister(self)
- capi.c_destruct(self.space, self.cppclass, self._rawobject)
+ capi.c_destruct(self.space, self.clsdecl, self._rawobject)
self._rawobject = capi.C_NULL_OBJECT
def _finalize_(self):
- if self.python_owns:
+ if self.flags & INSTANCE_FLAGS_PYTHON_OWNS:
self.destruct()
W_CPPClass.typedef = TypeDef(
'CPPClass',
- cppclass = interp_attrproperty_w('cppclass', cls=W_CPPClass),
- _python_owns = GetSetProperty(W_CPPClass.fget_python_owns, W_CPPClass.fset_python_owns),
+ __python_owns__ = GetSetProperty(W_CPPClass.fget_python_owns, W_CPPClass.fset_python_owns),
__init__ = interp2app(W_CPPClass.instance__init__),
__eq__ = interp2app(W_CPPClass.instance__eq__),
__ne__ = interp2app(W_CPPClass.instance__ne__),
@@ -1220,21 +1235,21 @@
state = space.fromcache(State)
return space.call_function(state.w_fngen_callback, w_callable, space.newint(npar))
-def wrap_cppobject(space, rawobject, cppclass,
- do_cast=True, python_owns=False, is_ref=False, fresh=False):
+def wrap_cppinstance(space, rawobject, clsdecl,
+ do_cast=True, python_owns=False, is_ref=False, fresh=False):
rawobject = rffi.cast(capi.C_OBJECT, rawobject)
# cast to actual if requested and possible
w_pycppclass = None
if do_cast and rawobject:
- actual = capi.c_actual_class(space, cppclass, rawobject)
- if actual != cppclass.handle:
+ actual = capi.c_actual_class(space, clsdecl, rawobject)
+ if actual != clsdecl.handle:
try:
w_pycppclass = get_pythonized_cppclass(space, actual)
- offset = capi.c_base_offset1(space, actual, cppclass, rawobject, -1)
+ offset = capi.c_base_offset1(space, actual, clsdecl, rawobject, -1)
rawobject = capi.direct_ptradd(rawobject, offset)
- w_cppclass = space.findattr(w_pycppclass, space.newtext("__cppdecl__"))
- cppclass = space.interp_w(W_CPPClassDecl, w_cppclass, can_be_None=False)
+ w_cppdecl = space.findattr(w_pycppclass, space.newtext("__cppdecl__"))
+ clsdecl = space.interp_w(W_CPPClassDecl, w_cppdecl, can_be_None=False)
except Exception:
# failed to locate/build the derived class, so stick to the base (note
# that only get_pythonized_cppclass is expected to raise, so none of
@@ -1242,18 +1257,18 @@
pass
if w_pycppclass is None:
- w_pycppclass = get_pythonized_cppclass(space, cppclass.handle)
+ w_pycppclass = get_pythonized_cppclass(space, clsdecl.handle)
# try to recycle existing object if this one is not newly created
if not fresh and rawobject:
obj = memory_regulator.retrieve(rawobject)
- if obj is not None and obj.cppclass is cppclass:
+ if obj is not None and obj.clsdecl is clsdecl:
return obj
# fresh creation
w_cppinstance = space.allocate_instance(W_CPPClass, w_pycppclass)
cppinstance = space.interp_w(W_CPPClass, w_cppinstance, can_be_None=False)
- cppinstance.__init__(space, cppclass, rawobject, is_ref, python_owns)
+ cppinstance.__init__(space, clsdecl, rawobject, is_ref, python_owns)
memory_regulator.register(cppinstance)
return w_cppinstance
@@ -1264,7 +1279,7 @@
except TypeError:
pass
# attempt to get address of C++ instance
- return rffi.cast(rffi.INTPTR_T, converter.get_rawobject(space, w_obj))
+ return rffi.cast(rffi.INTPTR_T, converter.get_rawobject(space, w_obj, False))
@unwrap_spec(w_obj=W_Root)
def addressof(space, w_obj):
@@ -1273,19 +1288,30 @@
return space.newlong(address)
@unwrap_spec(owns=bool, cast=bool)
-def bind_object(space, w_obj, w_pycppclass, owns=False, cast=False):
- """Takes an address and a bound C++ class proxy, returns a bound instance."""
+def _bind_object(space, w_obj, w_clsdecl, owns=False, cast=False):
try:
# attempt address from array or C++ instance
rawobject = rffi.cast(capi.C_OBJECT, _addressof(space, w_obj))
except Exception:
# accept integer value as address
rawobject = rffi.cast(capi.C_OBJECT, space.uint_w(w_obj))
- w_cppclass = space.findattr(w_pycppclass, space.newtext("__cppdecl__"))
- if not w_cppclass:
- w_cppclass = scope_byname(space, space.text_w(w_pycppclass))
- if not w_cppclass:
+ decl = space.interp_w(W_CPPClassDecl, w_clsdecl, can_be_None=False)
+ return wrap_cppinstance(space, rawobject, decl, python_owns=owns, do_cast=cast)
+
+ at unwrap_spec(owns=bool, cast=bool)
+def bind_object(space, w_obj, w_pycppclass, owns=False, cast=False):
More information about the pypy-commit
mailing list