aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatti Picus <matti.picus@gmail.com>2018-04-24 09:05:26 +0300
committerMatti Picus <matti.picus@gmail.com>2018-04-24 09:05:26 +0300
commit099f9a7a22285f3f6cb17601759eacc86ed4211a (patch)
tree5388e681f52d5eaf0edb06eb3677a77492dc0d32
parentmerge py3.5 into release (diff)
parentmerge default into branch (diff)
downloadpypy-099f9a7a22285f3f6cb17601759eacc86ed4211a.tar.gz
pypy-099f9a7a22285f3f6cb17601759eacc86ed4211a.tar.bz2
pypy-099f9a7a22285f3f6cb17601759eacc86ed4211a.zip
merge py3.5 into releaserelease-pypy3.5-v6.0.0
-rw-r--r--LICENSE2
-rw-r--r--lib-python/3/datetime.py23
-rw-r--r--lib_pypy/_cffi_ssl/README.md2
-rw-r--r--lib_pypy/_cffi_ssl/_cffi_src/openssl/pypy_win32_extra.py84
-rw-r--r--lib_pypy/_cffi_ssl/_stdssl/__init__.py1
-rw-r--r--lib_pypy/_cffi_ssl/_stdssl/win32_extra.py101
-rw-r--r--lib_pypy/_ssl/__init__.py20
-rw-r--r--lib_pypy/_ssl_build.py9
-rw-r--r--pypy/doc/contributor.rst2
-rw-r--r--pypy/doc/release-v6.0.0.rst12
-rw-r--r--pypy/doc/whatsnew-head.rst2
-rw-r--r--pypy/doc/whatsnew-pypy2-6.0.0.rst6
-rw-r--r--pypy/interpreter/executioncontext.py10
-rw-r--r--pypy/interpreter/test/test_executioncontext.py41
-rw-r--r--pypy/module/__pypy__/interp_pypydatetime.py2
-rw-r--r--pypy/module/_cppyy/__init__.py2
-rw-r--r--pypy/module/_cppyy/capi/loadable_capi.py93
-rw-r--r--pypy/module/_cppyy/converter.py30
-rw-r--r--pypy/module/_cppyy/executor.py2
-rw-r--r--pypy/module/_cppyy/include/capi.h74
-rw-r--r--pypy/module/_cppyy/interp_cppyy.py144
-rw-r--r--pypy/module/_cppyy/pythonify.py23
-rw-r--r--pypy/module/_cppyy/src/dummy_backend.cxx40
-rw-r--r--pypy/module/_cppyy/test/Makefile2
-rw-r--r--pypy/module/_cppyy/test/advancedcpp.cxx12
-rw-r--r--pypy/module/_cppyy/test/advancedcpp.h11
-rw-r--r--pypy/module/_cppyy/test/advancedcpp.xml2
-rw-r--r--pypy/module/_cppyy/test/conftest.py4
-rw-r--r--pypy/module/_cppyy/test/fragile.h2
-rw-r--r--pypy/module/_cppyy/test/test_advancedcpp.py19
-rw-r--r--pypy/module/_cppyy/test/test_overloads.py1
-rw-r--r--pypy/module/_cppyy/test/test_zjit.py3
-rw-r--r--pypy/module/cpyext/cdatetime.py2
-rw-r--r--pypy/module/cpyext/test/test_datetime.py18
-rw-r--r--pypy/objspace/std/listobject.py8
-rw-r--r--pypy/objspace/std/test/test_listobject.py9
36 files changed, 621 insertions, 197 deletions
diff --git a/LICENSE b/LICENSE
index 2f5d7f4ae4..438dc5c098 100644
--- a/LICENSE
+++ b/LICENSE
@@ -247,6 +247,7 @@ copyrighted by one or more of the following people and organizations:
Lukas Vacek
Omer Katz
Jacek Generowicz
+ Tomasz Dziopa
Sylvain Thenault
Jakub Stasiak
Andrew Dalke
@@ -307,6 +308,7 @@ copyrighted by one or more of the following people and organizations:
Yury V. Zaytsev
florinpapa
Anders Sigfridsson
+ Matt Jackson
Nikolay Zinov
rafalgalczynski@gmail.com
Joshua Gilbert
diff --git a/lib-python/3/datetime.py b/lib-python/3/datetime.py
index 33a9a892ae..7b9bcfd6c0 100644
--- a/lib-python/3/datetime.py
+++ b/lib-python/3/datetime.py
@@ -7,6 +7,9 @@ time zone and DST data sources.
import time as _time
import math as _math
+# for cpyext, use these as base classes
+from __pypy__._pypydatetime import dateinterop, deltainterop, timeinterop
+
def _cmp(x, y):
return 0 if x == y else 1 if x > y else -1
@@ -316,7 +319,7 @@ def _divide_and_round(a, b):
return q
-class timedelta:
+class timedelta(deltainterop):
"""Represent the difference between two datetime objects.
Supported operators:
@@ -429,7 +432,7 @@ class timedelta:
if abs(d) > 999999999:
raise OverflowError("timedelta # of days is too large: %d" % d)
- self = object.__new__(cls)
+ self = deltainterop.__new__(cls)
self._days = d
self._seconds = s
self._microseconds = us
@@ -638,7 +641,7 @@ timedelta.max = timedelta(days=999999999, hours=23, minutes=59, seconds=59,
microseconds=999999)
timedelta.resolution = timedelta(microseconds=1)
-class date:
+class date(dateinterop):
"""Concrete date type.
Constructors:
@@ -678,12 +681,12 @@ class date:
if month is None and isinstance(year, bytes) and len(year) == 4 and \
1 <= year[2] <= 12:
# Pickle support
- self = object.__new__(cls)
+ self = dateinterop.__new__(cls)
self.__setstate(year)
self._hashcode = -1
return self
year, month, day = _check_date_fields(year, month, day)
- self = object.__new__(cls)
+ self = dateinterop.__new__(cls)
self._year = year
self._month = month
self._day = day
@@ -1008,7 +1011,7 @@ class tzinfo:
_tzinfo_class = tzinfo
-class time:
+class time(timeinterop):
"""Time with time zone.
Constructors:
@@ -1044,14 +1047,14 @@ class time:
"""
if isinstance(hour, bytes) and len(hour) == 6 and hour[0] < 24:
# Pickle support
- self = object.__new__(cls)
+ self = timeinterop.__new__(cls)
self.__setstate(hour, minute or None)
self._hashcode = -1
return self
hour, minute, second, microsecond = _check_time_fields(
hour, minute, second, microsecond)
_check_tzinfo_arg(tzinfo)
- self = object.__new__(cls)
+ self = timeinterop.__new__(cls)
self._hour = hour
self._minute = minute
self._second = second
@@ -1329,7 +1332,7 @@ class datetime(date):
microsecond=0, tzinfo=None):
if isinstance(year, bytes) and len(year) == 10 and 1 <= year[2] <= 12:
# Pickle support
- self = object.__new__(cls)
+ self = dateinterop.__new__(cls)
self.__setstate(year, month)
self._hashcode = -1
return self
@@ -1337,7 +1340,7 @@ class datetime(date):
hour, minute, second, microsecond = _check_time_fields(
hour, minute, second, microsecond)
_check_tzinfo_arg(tzinfo)
- self = object.__new__(cls)
+ self = dateinterop.__new__(cls)
self._year = year
self._month = month
self._day = day
diff --git a/lib_pypy/_cffi_ssl/README.md b/lib_pypy/_cffi_ssl/README.md
index e2a56e6d5b..045f2b4228 100644
--- a/lib_pypy/_cffi_ssl/README.md
+++ b/lib_pypy/_cffi_ssl/README.md
@@ -14,6 +14,8 @@ NOTE: currently, we have the following changes:
* ``_cffi_src/openssl/x509_vfy.py`` for issue #2605 (ca4d0c90f5a1)
+* ``_cffi_src/openssl/pypy_win32_extra.py`` for Win32-only functionality like ssl.enum_certificates()
+
# Tests?
diff --git a/lib_pypy/_cffi_ssl/_cffi_src/openssl/pypy_win32_extra.py b/lib_pypy/_cffi_ssl/_cffi_src/openssl/pypy_win32_extra.py
new file mode 100644
index 0000000000..36abad1e32
--- /dev/null
+++ b/lib_pypy/_cffi_ssl/_cffi_src/openssl/pypy_win32_extra.py
@@ -0,0 +1,84 @@
+#
+# An extra bit of logic for the Win32-only functionality that is missing from the
+# version from cryptography.
+#
+
+import sys
+
+INCLUDES = """
+#include <Wincrypt.h>
+"""
+
+TYPES = """
+typedef ... *HCERTSTORE;
+typedef ... *HCRYPTPROV_LEGACY;
+
+typedef struct {
+ DWORD dwCertEncodingType;
+ BYTE *pbCertEncoded;
+ DWORD cbCertEncoded;
+ ...;
+} CERT_CONTEXT, *PCCERT_CONTEXT;
+
+typedef struct {
+ DWORD dwCertEncodingType;
+ BYTE *pbCrlEncoded;
+ DWORD cbCrlEncoded;
+ ...;
+} CRL_CONTEXT, *PCCRL_CONTEXT;
+
+typedef struct {
+ DWORD cUsageIdentifier;
+ LPSTR *rgpszUsageIdentifier;
+ ...;
+} CERT_ENHKEY_USAGE, *PCERT_ENHKEY_USAGE;
+"""
+
+FUNCTIONS = """
+HCERTSTORE WINAPI CertOpenStore(
+ LPCSTR lpszStoreProvider,
+ DWORD dwMsgAndCertEncodingType,
+ HCRYPTPROV_LEGACY hCryptProv,
+ DWORD dwFlags,
+ const char *pvPara
+);
+PCCERT_CONTEXT WINAPI CertEnumCertificatesInStore(
+ HCERTSTORE hCertStore,
+ PCCERT_CONTEXT pPrevCertContext
+);
+BOOL WINAPI CertFreeCertificateContext(
+ PCCERT_CONTEXT pCertContext
+);
+BOOL WINAPI CertFreeCRLContext(
+ PCCRL_CONTEXT pCrlContext
+);
+BOOL WINAPI CertCloseStore(
+ HCERTSTORE hCertStore,
+ DWORD dwFlags
+);
+BOOL WINAPI CertGetEnhancedKeyUsage(
+ PCCERT_CONTEXT pCertContext,
+ DWORD dwFlags,
+ PCERT_ENHKEY_USAGE pUsage,
+ DWORD *pcbUsage
+);
+PCCRL_CONTEXT WINAPI CertEnumCRLsInStore(
+ HCERTSTORE hCertStore,
+ PCCRL_CONTEXT pPrevCrlContext
+);
+"""
+
+MACROS = """
+#define CERT_STORE_READONLY_FLAG ...
+#define CERT_SYSTEM_STORE_LOCAL_MACHINE ...
+#define CRYPT_E_NOT_FOUND ...
+#define CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG ...
+#define CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG ...
+#define X509_ASN_ENCODING ...
+#define PKCS_7_ASN_ENCODING ...
+
+static const LPCSTR CERT_STORE_PROV_SYSTEM_A;
+"""
+
+CUSTOMIZATIONS = """
+"""
diff --git a/lib_pypy/_cffi_ssl/_stdssl/__init__.py b/lib_pypy/_cffi_ssl/_stdssl/__init__.py
index 81ecfb1747..eff9b7aefd 100644
--- a/lib_pypy/_cffi_ssl/_stdssl/__init__.py
+++ b/lib_pypy/_cffi_ssl/_stdssl/__init__.py
@@ -24,6 +24,7 @@ from select import select
from enum import IntEnum as _IntEnum
if sys.platform == 'win32':
+ from _cffi_ssl._stdssl.win32_extra import enum_certificates, enum_crls
HAVE_POLL = False
else:
from select import poll, POLLIN, POLLOUT
diff --git a/lib_pypy/_cffi_ssl/_stdssl/win32_extra.py b/lib_pypy/_cffi_ssl/_stdssl/win32_extra.py
new file mode 100644
index 0000000000..689e13057f
--- /dev/null
+++ b/lib_pypy/_cffi_ssl/_stdssl/win32_extra.py
@@ -0,0 +1,101 @@
+from _pypy_openssl import lib, ffi
+
+
+def enum_certificates(store_name):
+ """Retrieve certificates from Windows' cert store.
+
+store_name may be one of 'CA', 'ROOT' or 'MY'. The system may provide
+more cert storages, too. The function returns a list of (bytes,
+encoding_type, trust) tuples. The encoding_type flag can be interpreted
+with X509_ASN_ENCODING or PKCS_7_ASN_ENCODING. The trust setting is either
+a set of OIDs or the boolean True.
+ """
+ hStore = lib.CertOpenStore(lib.CERT_STORE_PROV_SYSTEM_A, 0, ffi.NULL,
+ lib.CERT_STORE_READONLY_FLAG | lib.CERT_SYSTEM_STORE_LOCAL_MACHINE,
+ bytes(store_name, "ascii"))
+ if hStore == ffi.NULL:
+ raise WindowsError(*ffi.getwinerror())
+
+ result = []
+ pCertCtx = ffi.NULL
+ try:
+ while True:
+ pCertCtx = lib.CertEnumCertificatesInStore(hStore, pCertCtx)
+ if pCertCtx == ffi.NULL:
+ break
+ cert = ffi.buffer(pCertCtx.pbCertEncoded, pCertCtx.cbCertEncoded)[:]
+ enc = certEncodingType(pCertCtx.dwCertEncodingType)
+ keyusage = parseKeyUsage(pCertCtx, lib.CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG)
+ if keyusage is True:
+ keyusage = parseKeyUsage(pCertCtx, lib.CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG)
+ result.append((cert, enc, keyusage))
+ finally:
+ if pCertCtx != ffi.NULL:
+ lib.CertFreeCertificateContext(pCertCtx)
+ if not lib.CertCloseStore(hStore, 0):
+ # This error case might shadow another exception.
+ raise WindowsError(*ffi.getwinerror())
+ return result
+
+
+def enum_crls(store_name):
+ """Retrieve CRLs from Windows' cert store.
+
+store_name may be one of 'CA', 'ROOT' or 'MY'. The system may provide
+more cert storages, too. The function returns a list of (bytes,
+encoding_type) tuples. The encoding_type flag can be interpreted with
+X509_ASN_ENCODING or PKCS_7_ASN_ENCODING."""
+ hStore = lib.CertOpenStore(lib.CERT_STORE_PROV_SYSTEM_A, 0, ffi.NULL,
+ lib.CERT_STORE_READONLY_FLAG | lib.CERT_SYSTEM_STORE_LOCAL_MACHINE,
+ bytes(store_name, "ascii"))
+ if hStore == ffi.NULL:
+ raise WindowsError(*ffi.getwinerror())
+
+ result = []
+ pCrlCtx = ffi.NULL
+ try:
+ while True:
+ pCrlCtx = lib.CertEnumCRLsInStore(hStore, pCrlCtx)
+ if pCrlCtx == ffi.NULL:
+ break
+ crl = ffi.buffer(pCrlCtx.pbCrlEncoded, pCrlCtx.cbCrlEncoded)[:]
+ enc = certEncodingType(pCrlCtx.dwCertEncodingType)
+ result.append((crl, enc))
+ finally:
+ if pCrlCtx != ffi.NULL:
+ lib.CertFreeCRLContext(pCrlCtx)
+ if not lib.CertCloseStore(hStore, 0):
+ # This error case might shadow another exception.
+ raise WindowsError(*ffi.getwinerror())
+ return result
+
+
+def certEncodingType(encodingType):
+ if encodingType == lib.X509_ASN_ENCODING:
+ return "x509_asn"
+ if encodingType == lib.PKCS_7_ASN_ENCODING:
+ return "pkcs_7_asn"
+ return encodingType
+
+def parseKeyUsage(pCertCtx, flags):
+ pSize = ffi.new("DWORD *")
+ if not lib.CertGetEnhancedKeyUsage(pCertCtx, flags, ffi.NULL, pSize):
+ error_with_message = ffi.getwinerror()
+ if error_with_message[0] == lib.CRYPT_E_NOT_FOUND:
+ return True
+ raise WindowsError(*error_with_message)
+
+ pUsageMem = ffi.new("char[]", pSize[0])
+ pUsage = ffi.cast("PCERT_ENHKEY_USAGE", pUsageMem)
+ if not lib.CertGetEnhancedKeyUsage(pCertCtx, flags, pUsage, pSize):
+ error_with_message = ffi.getwinerror()
+ if error_with_message[0] == lib.CRYPT_E_NOT_FOUND:
+ return True
+ raise WindowsError(*error_with_message)
+
+ retval = set()
+ for i in range(pUsage.cUsageIdentifier):
+ if pUsage.rgpszUsageIdentifier[i]:
+ oid = ffi.string(pUsage.rgpszUsageIdentifier[i]).decode('ascii')
+ retval.add(oid)
+ return retval
diff --git a/lib_pypy/_ssl/__init__.py b/lib_pypy/_ssl/__init__.py
index d5933bf5fd..ca201981cd 100644
--- a/lib_pypy/_ssl/__init__.py
+++ b/lib_pypy/_ssl/__init__.py
@@ -16,12 +16,14 @@ if hasattr(_stdssl, 'RAND_egd'):
RAND_egd = builtinify(RAND_egd)
import sys
-if sys.platform == "win32" and 'enum_certificates' not in globals():
- def enum_certificates(*args, **kwds):
- import warnings
- warnings.warn("ssl.enum_certificates() is not implemented")
- return []
- def enum_crls(*args, **kwds):
- import warnings
- warnings.warn("ssl.enum_crls() is not implemented")
- return []
+if sys.platform == "win32":
+ if 'enum_certificates' not in globals():
+ def enum_certificates(*args, **kwds):
+ import warnings
+ warnings.warn("ssl.enum_certificates() is not implemented")
+ return []
+ if 'enum_crls' not in globals():
+ def enum_crls(*args, **kwds):
+ import warnings
+ warnings.warn("ssl.enum_crls() is not implemented")
+ return []
diff --git a/lib_pypy/_ssl_build.py b/lib_pypy/_ssl_build.py
index 7fb1cd3e9f..bd33a7e599 100644
--- a/lib_pypy/_ssl_build.py
+++ b/lib_pypy/_ssl_build.py
@@ -5,6 +5,11 @@ sys.modules['_cffi_src'] = _cffi_src
from _cffi_ssl._cffi_src.build_openssl import (build_ffi_for_binding,
_get_openssl_libraries, extra_link_args, compiler_type)
+if sys.platform == "win32":
+ pypy_win32_extra = ["pypy_win32_extra"]
+else:
+ pypy_win32_extra = []
+
ffi = build_ffi_for_binding(
module_name="_pypy_openssl",
module_prefix="_cffi_src.openssl.",
@@ -44,10 +49,10 @@ ffi = build_ffi_for_binding(
"x509_vfy",
"pkcs7",
"callbacks",
- ],
+ ] + pypy_win32_extra,
libraries=_get_openssl_libraries(sys.platform),
extra_link_args=extra_link_args(compiler_type()),
)
if __name__ == '__main__':
- ffi.compile()
+ ffi.compile(verbose=True)
diff --git a/pypy/doc/contributor.rst b/pypy/doc/contributor.rst
index 91e62bc6c7..0069d69c3f 100644
--- a/pypy/doc/contributor.rst
+++ b/pypy/doc/contributor.rst
@@ -214,6 +214,7 @@ Contributors
Lukas Vacek
Omer Katz
Jacek Generowicz
+ Tomasz Dziopa
Sylvain Thenault
Jakub Stasiak
Andrew Dalke
@@ -274,6 +275,7 @@ Contributors
Yury V. Zaytsev
florinpapa
Anders Sigfridsson
+ Matt Jackson
Nikolay Zinov
rafalgalczynski@gmail.com
Joshua Gilbert
diff --git a/pypy/doc/release-v6.0.0.rst b/pypy/doc/release-v6.0.0.rst
index 8a8cb893fb..53e6931797 100644
--- a/pypy/doc/release-v6.0.0.rst
+++ b/pypy/doc/release-v6.0.0.rst
@@ -20,16 +20,18 @@ getting started writing code. We have improved our parser to emit more friendly
The GC now has `hooks`_ to gain more insights into its performance
-The Windows PyPy3.5 release is still considered beta-quality. There are open
-issues with unicode handling especially around system calls and c-extensions.
-
The Matplotlib TkAgg backend now works with PyPy, as do pygame and pygobject_.
+We updated the `cffi`_ module included in PyPy to version 1.11.5, and the
+`cppyy`_ backend to 0.6.0. Please use these to wrap your C and C++ code,
+respectively, for a JIT friendly experience.
+
As always, this release is 100% compatible with the previous one and fixed
several issues and bugs raised by the growing community of PyPy users.
We strongly recommend updating.
-We updated the cffi module included in PyPy to version 1.11.5
+The Windows PyPy3.5 release is still considered beta-quality. There are open
+issues with unicode handling especially around system calls and c-extensions.
The utf8 branch that changes internal representation of unicode to utf8 did not
make it into the release, so there is still more goodness coming. We also
@@ -56,6 +58,8 @@ on pypy, or general `help`_ with making RPython's JIT even better.
.. _pygobject: https://lazka.github.io/posts/2018-04_pypy-pygobject/index.html
.. _`syntax errors`: https://morepypy.blogspot.com/2018/04/improving-syntaxerror-in-pypy.html
.. _`hooks`: gc_info.html#gc-hooks
+.. _`cffi`: http://cffi.readthedocs.io
+.. _`cppyy`: https://cppyy.readthedocs.io
What is PyPy?
=============
diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
index 0a1e683bdc..444962b691 100644
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -3,7 +3,7 @@ What's new in PyPy2.7 6.0+
==========================
.. this is a revision shortly after release-pypy-6.0.0
-.. startrev: ad79cc0ce9a8
+.. startrev: e50e11af23f1
diff --git a/pypy/doc/whatsnew-pypy2-6.0.0.rst b/pypy/doc/whatsnew-pypy2-6.0.0.rst
index fa781af23d..61a4e36b33 100644
--- a/pypy/doc/whatsnew-pypy2-6.0.0.rst
+++ b/pypy/doc/whatsnew-pypy2-6.0.0.rst
@@ -125,4 +125,8 @@ Introduce GC hooks, as documented in doc/gc_info.rst
.. branch: gc-hook-better-timestamp
-Improve GC hooksd
+Improve GC hooks
+
+.. branch: cppyy-packaging
+
+Update backend to 0.6.0 and support exceptions through wrappers
diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py
index f75681128a..943eef1f36 100644
--- a/pypy/interpreter/executioncontext.py
+++ b/pypy/interpreter/executioncontext.py
@@ -479,11 +479,17 @@ class AbstractActionFlag(object):
# 'action.fire()' happens to be called any time before
# the corresponding perform(), the fire() has no
# effect---which is the effect we want, because
- # perform() will be called anyway.
+ # perform() will be called anyway. All such pending
+ # actions with _fired == True are still inside the old
+ # chained list. As soon as we reset _fired to False,
+ # we also reset _next to None and we are ready for
+ # another fire().
while action is not None:
+ next_action = action._next
+ action._next = None
action._fired = False
action.perform(ec, frame)
- action._next, action = None, action._next
+ action = next_action
self.action_dispatcher = action_dispatcher
diff --git a/pypy/interpreter/test/test_executioncontext.py b/pypy/interpreter/test/test_executioncontext.py
index fa8b970308..2e8ac663f7 100644
--- a/pypy/interpreter/test/test_executioncontext.py
+++ b/pypy/interpreter/test/test_executioncontext.py
@@ -66,6 +66,47 @@ class TestExecutionContext:
""")
assert events == ['one']
+ def test_fire_inside_perform(self):
+ # test what happens if we call AsyncAction.fire() while we are in the
+ # middle of an AsyncAction.perform(). In particular, this happens when
+ # PyObjectDeallocAction.fire() is called by rawrefcount: see issue
+ # 2805
+ events = []
+
+ class Action1(executioncontext.AsyncAction):
+ _count = 0
+
+ def perform(self, ec, frame):
+ events.append('one')
+ if self._count == 0:
+ # a1 is no longer in the queue, so it will be enqueued
+ a1.fire()
+ #
+ # a2 is still in the queue, so the fire() is ignored and
+ # it's performed in its normal order, i.e. BEFORE a3
+ a2.fire()
+ self._count += 1
+
+ class Action2(executioncontext.AsyncAction):
+ def perform(self, ec, frame):
+ events.append('two')
+
+ class Action3(executioncontext.AsyncAction):
+ def perform(self, ec, frame):
+ events.append('three')
+
+ space = self.space
+ a1 = Action1(space)
+ a2 = Action2(space)
+ a3 = Action3(space)
+ a1.fire()
+ a2.fire()
+ a3.fire()
+ space.appexec([], """():
+ pass
+ """)
+ assert events == ['one', 'two', 'three', 'one']
+
def test_periodic_action(self):
from pypy.interpreter.executioncontext import ActionFlag
diff --git a/pypy/module/__pypy__/interp_pypydatetime.py b/pypy/module/__pypy__/interp_pypydatetime.py
index 994235af81..2150fdd558 100644
--- a/pypy/module/__pypy__/interp_pypydatetime.py
+++ b/pypy/module/__pypy__/interp_pypydatetime.py
@@ -5,7 +5,7 @@ from rpython.tool.sourcetools import func_with_new_name
def create_class(name):
class W_Class(W_Root):
- 'builtin base clasee for datetime.%s to allow interop with cpyext' % name
+ 'builtin base class for datetime.%s to allow interop with cpyext' % name
def descr_new__(space, w_type):
return space.allocate_instance(W_Class, w_type)
diff --git a/pypy/module/_cppyy/__init__.py b/pypy/module/_cppyy/__init__.py
index 3c6eb6f31c..d8181b077b 100644
--- a/pypy/module/_cppyy/__init__.py
+++ b/pypy/module/_cppyy/__init__.py
@@ -13,7 +13,7 @@ class Module(MixedModule):
'_set_function_generator': 'interp_cppyy.set_function_generator',
'_register_class' : 'interp_cppyy.register_class',
'_get_nullptr' : 'interp_cppyy.get_nullptr',
- 'CPPClassBase' : 'interp_cppyy.W_CPPClass',
+ 'CPPInstanceBase' : 'interp_cppyy.W_CPPInstance',
'addressof' : 'interp_cppyy.addressof',
'_bind_object' : 'interp_cppyy._bind_object',
'bind_object' : 'interp_cppyy.bind_object',
diff --git a/pypy/module/_cppyy/capi/loadable_capi.py b/pypy/module/_cppyy/capi/loadable_capi.py
index d54dd86167..1860fc44fe 100644
--- a/pypy/module/_cppyy/capi/loadable_capi.py
+++ b/pypy/module/_cppyy/capi/loadable_capi.py
@@ -121,11 +121,11 @@ class State(object):
# TODO: the following need to match up with the globally defined C_XYZ low-level
# types (see capi/__init__.py), but by using strings here, that isn't guaranteed
- c_opaque_ptr = state.c_ulong
+ c_opaque_ptr = state.c_ulong # not ptrdiff_t (which is signed)
c_scope = c_opaque_ptr
c_type = c_scope
- c_object = c_opaque_ptr
+ c_object = c_opaque_ptr # not voidp (to stick with one handle type)
c_method = c_opaque_ptr
c_index = state.c_long
c_index_array = state.c_voidp
@@ -150,16 +150,17 @@ class State(object):
self.capi_call_ifaces = {
# name to opaque C++ scope representation
- 'num_scopes' : ([c_scope], c_int),
- 'scope_name' : ([c_scope, c_int], c_ccharp),
-
'resolve_name' : ([c_ccharp], c_ccharp),
+ 'resolve_enum' : ([c_ccharp], c_ccharp),
'get_scope' : ([c_ccharp], c_scope),
'actual_class' : ([c_type, c_object], c_type),
+ 'size_of_klass' : ([c_type], c_size_t),
+ 'size_of_type' : ([c_ccharp], c_size_t),
# memory management
'allocate' : ([c_type], c_object),
'deallocate' : ([c_type, c_object], c_void),
+ 'construct' : ([c_type], c_object),
'destruct' : ([c_type, c_object], c_void),
# method/function dispatching
@@ -182,7 +183,8 @@ class State(object):
'constructor' : ([c_method, c_object, c_int, c_voidp], c_object),
'call_o' : ([c_method, c_object, c_int, c_voidp, c_type], c_object),
- 'get_function_address' : ([c_scope, c_index], c_voidp), # TODO: verify
+ 'function_address_from_index' : ([c_scope, c_index], c_voidp), # TODO: verify
+ 'function_address_from_method' : ([c_method], c_voidp), # id.
# handling of function argument buffer
'allocate_function_args' : ([c_int], c_voidp),
@@ -196,6 +198,8 @@ class State(object):
'is_abstract' : ([c_type], c_int),
'is_enum' : ([c_ccharp], c_int),
+ 'get_all_cpp_names' : ([c_scope, c_voidp], c_voidp), # const char**
+
# type/class reflection information
'final_name' : ([c_type], c_ccharp),
'scoped_final_name' : ([c_type], c_ccharp),
@@ -208,10 +212,10 @@ class State(object):
# method/function reflection information
'num_methods' : ([c_scope], c_int),
- 'method_index_at' : ([c_scope, c_int], c_index),
'method_indices_from_name' : ([c_scope, c_ccharp], c_index_array),
'method_name' : ([c_scope, c_index], c_ccharp),
+ 'method_mangled_name' : ([c_scope, c_index], c_ccharp),
'method_result_type' : ([c_scope, c_index], c_ccharp),
'method_num_args' : ([c_scope, c_index], c_int),
'method_req_args' : ([c_scope, c_index], c_int),
@@ -219,7 +223,9 @@ class State(object):
'method_arg_default' : ([c_scope, c_index, c_int], c_ccharp),
'method_signature' : ([c_scope, c_index, c_int], c_ccharp),
'method_prototype' : ([c_scope, c_index, c_int], c_ccharp),
+ 'is_const_method' : ([c_method], c_int),
+ 'exists_method_template' : ([c_scope, c_ccharp], c_int),
'method_is_template' : ([c_scope, c_index], c_int),
'method_num_template_args' : ([c_scope, c_index], c_int),
'method_template_arg_name' : ([c_scope, c_index, c_index], c_ccharp),
@@ -228,7 +234,9 @@ class State(object):
'get_global_operator' : ([c_scope, c_scope, c_scope, c_ccharp], c_index),
# method properties
+ 'is_public_method' : ([c_type, c_index], c_int),
'is_constructor' : ([c_type, c_index], c_int),
+ 'is_destructor' : ([c_type, c_index], c_int),
'is_staticmethod' : ([c_type, c_index], c_int),
# data member reflection information
@@ -236,12 +244,14 @@ class State(object):
'datamember_name' : ([c_scope, c_int], c_ccharp),
'datamember_type' : ([c_scope, c_int], c_ccharp),
'datamember_offset' : ([c_scope, c_int], c_ptrdiff_t),
-
'datamember_index' : ([c_scope, c_ccharp], c_int),
# data member properties
'is_publicdata' : ([c_scope, c_int], c_int),
'is_staticdata' : ([c_scope, c_int], c_int),
+ 'is_const_data' : ([c_scope, c_int], c_int),
+ 'is_enum_data' : ([c_scope, c_int], c_int),
+ 'get_dimension_size' : ([c_scope, c_int, c_int], c_int),
# misc helpers
'strtoll' : ([c_ccharp], c_llong),
@@ -328,25 +338,27 @@ def _cdata_to_ccharp(space, w_cdata):
return rffi.cast(rffi.CCHARP, ptr)
# name to opaque C++ scope representation ------------------------------------
-def c_num_scopes(space, cppscope):
- return space.int_w(call_capi(space, 'num_scopes', [_ArgH(cppscope.handle)]))
-def c_scope_name(space, cppscope, iscope):
- args = [_ArgH(cppscope.handle), _ArgL(iscope)]
- return charp2str_free(space, call_capi(space, 'scope_name', args))
-
def c_resolve_name(space, name):
return charp2str_free(space, call_capi(space, 'resolve_name', [_ArgS(name)]))
+def c_resolve_enum(space, name):
+ return charp2str_free(space, call_capi(space, 'resolve_enum', [_ArgS(name)]))
def c_get_scope_opaque(space, name):
return rffi.cast(C_SCOPE, space.uint_w(call_capi(space, 'get_scope', [_ArgS(name)])))
def c_actual_class(space, cppclass, cppobj):
args = [_ArgH(cppclass.handle), _ArgH(cppobj)]
return rffi.cast(C_TYPE, space.uint_w(call_capi(space, 'actual_class', args)))
+def c_size_of_klass(space, cppclass):
+ return _cdata_to_size_t(space, call_capi(space, 'size_of_klass', [_ArgH(cppclass.handle)]))
+def c_size_of_type(space, name):
+ return _cdata_to_size_t(space, call_capi(space, 'size_of_type', [_ArgS(name)]))
# memory management ----------------------------------------------------------
def c_allocate(space, cppclass):
return _cdata_to_cobject(space, call_capi(space, 'allocate', [_ArgH(cppclass.handle)]))
def c_deallocate(space, cppclass, cppobject):
call_capi(space, 'deallocate', [_ArgH(cppclass.handle), _ArgH(cppobject)])
+def c_construct(space, cppclass):
+ return _cdata_to_cobject(space, call_capi(space, 'construct', [_ArgH(cppclass.handle)]))
def c_destruct(space, cppclass, cppobject):
call_capi(space, 'destruct', [_ArgH(cppclass.handle), _ArgH(cppobject)])
@@ -391,7 +403,7 @@ def c_call_s(space, cppmethod, cppobject, nargs, cargs):
w_cstr = call_capi(space, 'call_s',
[_ArgH(cppmethod), _ArgH(cppobject), _ArgL(nargs), _ArgP(cargs),
_ArgP(rffi.cast(rffi.VOIDP, length))])
- cstr_len = intmask(length[0])
+ cstr_len = int(intmask(length[0]))
finally:
lltype.free(length, flavor='raw')
return _cdata_to_ccharp(space, w_cstr), cstr_len
@@ -403,10 +415,13 @@ def c_call_o(space, cppmethod, cppobject, nargs, cargs, cppclass):
args = [_ArgH(cppmethod), _ArgH(cppobject), _ArgL(nargs), _ArgP(cargs), _ArgH(cppclass.handle)]
return _cdata_to_cobject(space, call_capi(space, 'call_o', args))
-def c_get_function_address(space, cppscope, index):
+def c_function_address_from_index(space, cppscope, index):
args = [_ArgH(cppscope.handle), _ArgL(index)]
return rffi.cast(C_FUNC_PTR,
- _cdata_to_ptr(space, call_capi(space, 'get_function_address', args)))
+ _cdata_to_ptr(space, call_capi(space, 'function_address_from_index', args)))
+def c_function_address_from_method(space, cppmethod):
+ return rffi.cast(C_FUNC_PTR,
+ _cdata_to_ptr(space, call_capi(space, 'function_address_from_method', _ArgH(cppmethod))))
# handling of function argument buffer ---------------------------------------
def c_allocate_function_args(space, size):
@@ -430,6 +445,23 @@ def c_is_abstract(space, cpptype):
def c_is_enum(space, name):
return space.bool_w(call_capi(space, 'is_enum', [_ArgS(name)]))
+def c_get_all_cpp_names(space, scope):
+ sz = lltype.malloc(rffi.SIZE_TP.TO, 1, flavor='raw', zero=True)
+ try:
+ args = [_ArgH(scope.handle), _ArgP(rffi.cast(rffi.VOIDP, sz))]
+ rawnames = rffi.cast(rffi.CCHARPP,
+ _cdata_to_ptr(space, call_capi(space, 'get_all_cpp_names', args)))
+ count = int(intmask(sz[0]))
+ finally:
+ lltype.free(sz, flavor='raw')
+ allnames = []
+ for i in range(count):
+ pystr = rffi.charp2str(rawnames[i])
+ c_free(space, rffi.cast(rffi.VOIDP, rawnames[i])) # c_free defined below
+ allnames.append(pystr)
+ c_free(space, rffi.cast(rffi.VOIDP, rawnames)) # id.
+ return allnames
+
# type/class reflection information ------------------------------------------
def c_final_name(space, cpptype):
return charp2str_free(space, call_capi(space, 'final_name', [_ArgH(cpptype)]))
@@ -462,13 +494,10 @@ def c_base_offset1(space, derived_h, base, address, direction):
def c_num_methods(space, cppscope):
args = [_ArgH(cppscope.handle)]
return space.int_w(call_capi(space, 'num_methods', args))
-def c_method_index_at(space, cppscope, imethod):
- args = [_ArgH(cppscope.handle), _ArgL(imethod)]
- return space.int_w(call_capi(space, 'method_index_at', args))
def c_method_indices_from_name(space, cppscope, name):
args = [_ArgH(cppscope.handle), _ArgS(name)]
indices = rffi.cast(C_INDEX_ARRAY,
- _cdata_to_ptr(space, call_capi(space, 'method_indices_from_name', args)))
+ _cdata_to_ptr(space, call_capi(space, 'method_indices_from_name', args)))
if not indices:
return []
py_indices = []
@@ -506,6 +535,9 @@ 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_exists_method_template(space, cppscope, name):
+ args = [_ArgH(cppscope.handle), _ArgS(name)]
+ return space.bool_w(call_capi(space, 'exists_method_template', args))
def c_method_is_template(space, cppscope, index):
args = [_ArgH(cppscope.handle), _ArgL(index)]
return space.bool_w(call_capi(space, 'method_is_template', args))
@@ -531,9 +563,15 @@ def c_get_global_operator(space, nss, lc, rc, op):
return rffi.cast(WLAVC_INDEX, -1)
# method properties ----------------------------------------------------------
+def c_is_public_method(space, cppclass, index):
+ args = [_ArgH(cppclass.handle), _ArgL(index)]
+ return space.bool_w(call_capi(space, 'is_public_method', args))
def c_is_constructor(space, cppclass, index):
args = [_ArgH(cppclass.handle), _ArgL(index)]
return space.bool_w(call_capi(space, 'is_constructor', args))
+def c_is_destructor(space, cppclass, index):
+ args = [_ArgH(cppclass.handle), _ArgL(index)]
+ return space.bool_w(call_capi(space, 'is_destructor', args))
def c_is_staticmethod(space, cppclass, index):
args = [_ArgH(cppclass.handle), _ArgL(index)]
return space.bool_w(call_capi(space, 'is_staticmethod', args))
@@ -562,6 +600,15 @@ def c_is_publicdata(space, cppscope, datamember_index):
def c_is_staticdata(space, cppscope, datamember_index):
args = [_ArgH(cppscope.handle), _ArgL(datamember_index)]
return space.bool_w(call_capi(space, 'is_staticdata', args))
+def c_is_const_data(space, cppscope, datamember_index):
+ args = [_ArgH(cppscope.handle), _ArgL(datamember_index)]
+ return space.bool_w(call_capi(space, 'is_const_data', args))
+def c_is_enum_data(space, cppscope, datamember_index):
+ args = [_ArgH(cppscope.handle), _ArgL(datamember_index)]
+ return space.bool_w(call_capi(space, 'is_enum_data', args))
+def c_get_dimension_size(space, cppscope, datamember_index, dim_idx):
+ args = [_ArgH(cppscope.handle), _ArgL(datamember_index), _ArgL(dim_idx)]
+ return space.bool_w(call_capi(space, 'get_dimension_size', args))
# misc helpers ---------------------------------------------------------------
def c_strtoll(space, svalue):
@@ -585,7 +632,7 @@ def c_stdstring2charp(space, cppstr):
try:
w_cstr = call_capi(space, 'stdstring2charp',
[_ArgH(cppstr), _ArgP(rffi.cast(rffi.VOIDP, sz))])
- cstr_len = intmask(sz[0])
+ cstr_len = int(intmask(sz[0]))
finally:
lltype.free(sz, flavor='raw')
return rffi.charpsize2str(_cdata_to_ccharp(space, w_cstr), cstr_len)
@@ -607,7 +654,7 @@ def stdstring_c_str(space, w_self):
"""Return a python string taking into account \0"""
from pypy.module._cppyy import interp_cppyy
- cppstr = space.interp_w(interp_cppyy.W_CPPClass, w_self, can_be_None=False)
+ cppstr = space.interp_w(interp_cppyy.W_CPPInstance, w_self, can_be_None=False)
return space.newtext(c_stdstring2charp(space, cppstr._rawobject))
# setup pythonizations for later use at run-time
diff --git a/pypy/module/_cppyy/converter.py b/pypy/module/_cppyy/converter.py
index 6087951d11..83931137e4 100644
--- a/pypy/module/_cppyy/converter.py
+++ b/pypy/module/_cppyy/converter.py
@@ -22,8 +22,8 @@ from pypy.module._cppyy import helper, capi, ffitypes
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=can_be_None)
+ from pypy.module._cppyy.interp_cppyy import W_CPPInstance
+ cppinstance = space.interp_w(W_CPPInstance, w_obj, can_be_None=can_be_None)
if cppinstance:
rawobject = cppinstance.get_rawobject()
assert lltype.typeOf(rawobject) == capi.C_OBJECT
@@ -31,15 +31,15 @@ def get_rawobject(space, w_obj, can_be_None=True):
return capi.C_NULL_OBJECT
def set_rawobject(space, w_obj, address):
- from pypy.module._cppyy.interp_cppyy import W_CPPClass
- cppinstance = space.interp_w(W_CPPClass, w_obj, can_be_None=True)
+ from pypy.module._cppyy.interp_cppyy import W_CPPInstance
+ cppinstance = space.interp_w(W_CPPInstance, w_obj, can_be_None=True)
if cppinstance:
assert lltype.typeOf(cppinstance._rawobject) == capi.C_OBJECT
cppinstance._rawobject = rffi.cast(capi.C_OBJECT, address)
def get_rawobject_nonnull(space, w_obj):
- from pypy.module._cppyy.interp_cppyy import W_CPPClass
- cppinstance = space.interp_w(W_CPPClass, w_obj, can_be_None=True)
+ from pypy.module._cppyy.interp_cppyy import W_CPPInstance
+ cppinstance = space.interp_w(W_CPPInstance, w_obj, can_be_None=True)
if cppinstance:
cppinstance._nullcheck()
rawobject = cppinstance.get_rawobject()
@@ -502,8 +502,8 @@ class InstanceRefConverter(TypeConverter):
self.clsdecl = clsdecl
def _unwrap_object(self, space, w_obj):
- from pypy.module._cppyy.interp_cppyy import W_CPPClass
- if isinstance(w_obj, W_CPPClass):
+ from pypy.module._cppyy.interp_cppyy import W_CPPInstance
+ if isinstance(w_obj, W_CPPInstance):
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
@@ -534,8 +534,8 @@ class InstanceRefConverter(TypeConverter):
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):
+ from pypy.module._cppyy.interp_cppyy import W_CPPInstance, INSTANCE_FLAGS_IS_R_VALUE
+ if isinstance(w_obj, W_CPPInstance):
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)
@@ -598,8 +598,8 @@ class InstancePtrPtrConverter(InstancePtrConverter):
raise FastCallNotPossible
def finalize_call(self, space, w_obj, call_local):
- from pypy.module._cppyy.interp_cppyy import W_CPPClass
- assert isinstance(w_obj, W_CPPClass)
+ from pypy.module._cppyy.interp_cppyy import W_CPPInstance
+ assert isinstance(w_obj, W_CPPInstance)
r = rffi.cast(rffi.VOIDPP, call_local)
w_obj._rawobject = rffi.cast(capi.C_OBJECT, r[0])
@@ -617,8 +617,8 @@ class StdStringConverter(InstanceConverter):
InstanceConverter.__init__(self, space, cppclass)
def _unwrap_object(self, space, w_obj):
- from pypy.module._cppyy.interp_cppyy import W_CPPClass
- if isinstance(w_obj, W_CPPClass):
+ from pypy.module._cppyy.interp_cppyy import W_CPPInstance
+ if isinstance(w_obj, W_CPPInstance):
arg = InstanceConverter._unwrap_object(self, space, w_obj)
return capi.c_stdstring2stdstring(space, arg)
else:
@@ -749,8 +749,6 @@ def get_converter(space, _name, default):
return InstancePtrPtrConverter(space, clsdecl)
elif compound == "":
return InstanceConverter(space, clsdecl)
- elif capi.c_is_enum(space, clean_name):
- return _converters['unsigned'](space, default)
# 5) void* or void converter (which fails on use)
if 0 <= compound.find('*'):
diff --git a/pypy/module/_cppyy/executor.py b/pypy/module/_cppyy/executor.py
index 0a9be93ec7..22c3f73836 100644
--- a/pypy/module/_cppyy/executor.py
+++ b/pypy/module/_cppyy/executor.py
@@ -293,8 +293,6 @@ def get_executor(space, name):
return InstancePtrExecutor(space, cppclass)
elif compound == '**' or compound == '*&':
return InstancePtrPtrExecutor(space, cppclass)
- elif capi.c_is_enum(space, clean_name):
- return _executors['internal_enum_type_t'](space, None)
# 4) additional special cases
if compound == '*':
diff --git a/pypy/module/_cppyy/include/capi.h b/pypy/module/_cppyy/include/capi.h
index b232764c41..21e225d9d3 100644
--- a/pypy/module/_cppyy/include/capi.h
+++ b/pypy/module/_cppyy/include/capi.h
@@ -8,26 +8,29 @@
extern "C" {
#endif // ifdef __cplusplus
- typedef unsigned long cppyy_scope_t;
+ typedef ptrdiff_t cppyy_scope_t;
typedef cppyy_scope_t cppyy_type_t;
- typedef unsigned long cppyy_object_t;
- typedef unsigned long cppyy_method_t;
+ typedef void* cppyy_object_t;
+ typedef ptrdiff_t cppyy_method_t;
+
typedef long cppyy_index_t;
typedef void* cppyy_funcaddr_t;
+ typedef unsigned long cppyy_exctype_t;
+
/* name to opaque C++ scope representation -------------------------------- */
RPY_EXTERN
- int cppyy_num_scopes(cppyy_scope_t parent);
- RPY_EXTERN
- char* cppyy_scope_name(cppyy_scope_t parent, cppyy_index_t iscope);
- RPY_EXTERN
char* cppyy_resolve_name(const char* cppitem_name);
RPY_EXTERN
+ char* cppyy_resolve_enum(const char* enum_type);
+ 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);
+ size_t cppyy_size_of_klass(cppyy_type_t klass);
+ RPY_EXTERN
+ size_t cppyy_size_of_type(const char* type_name);
/* memory management ------------------------------------------------------ */
RPY_EXTERN
@@ -35,48 +38,53 @@ extern "C" {
RPY_EXTERN
void cppyy_deallocate(cppyy_type_t type, cppyy_object_t self);
RPY_EXTERN
+ cppyy_object_t cppyy_construct(cppyy_type_t type);
+ RPY_EXTERN
void cppyy_destruct(cppyy_type_t type, cppyy_object_t self);
/* method/function dispatching -------------------------------------------- */
RPY_EXTERN
- void cppyy_call_v(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+ void cppyy_call_v(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
RPY_EXTERN
unsigned char cppyy_call_b(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
RPY_EXTERN
- char cppyy_call_c(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+ char cppyy_call_c(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
RPY_EXTERN
- short cppyy_call_h(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+ short cppyy_call_h(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
RPY_EXTERN
- int cppyy_call_i(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+ int cppyy_call_i(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
RPY_EXTERN
- long cppyy_call_l(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+ long cppyy_call_l(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
RPY_EXTERN
long long cppyy_call_ll(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
RPY_EXTERN
- float cppyy_call_f(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+ float cppyy_call_f(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
RPY_EXTERN
double cppyy_call_d(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
RPY_EXTERN
long double cppyy_call_ld(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
RPY_EXTERN
- void* cppyy_call_r(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+ void* cppyy_call_r(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
RPY_EXTERN
- char* cppyy_call_s(cppyy_method_t method, cppyy_object_t self, int nargs, void* args, size_t* length);
-
+ char* cppyy_call_s(cppyy_method_t method, cppyy_object_t self, int nargs, void* args, size_t* length);
RPY_EXTERN
cppyy_object_t cppyy_constructor(cppyy_method_t method, cppyy_type_t klass, int nargs, void* args);
RPY_EXTERN
+ void cppyy_destructor(cppyy_type_t type, cppyy_object_t self);
+ RPY_EXTERN
cppyy_object_t cppyy_call_o(cppyy_method_t method, cppyy_object_t self, int nargs, void* args, cppyy_type_t result_type);
RPY_EXTERN
- cppyy_funcaddr_t cppyy_get_function_address(cppyy_scope_t scope, cppyy_index_t idx);
+ cppyy_funcaddr_t cppyy_function_address_from_index(cppyy_scope_t scope, cppyy_index_t idx);
+ RPY_EXTERN
+ cppyy_funcaddr_t cppyy_function_address_from_method(cppyy_method_t method);
/* handling of function argument buffer ----------------------------------- */
RPY_EXTERN
- void* cppyy_allocate_function_args(int nargs);
+ void* cppyy_allocate_function_args(int nargs);
RPY_EXTERN
- void cppyy_deallocate_function_args(void* args);
+ void cppyy_deallocate_function_args(void* args);
RPY_EXTERN
size_t cppyy_function_arg_sizeof();
RPY_EXTERN
@@ -92,6 +100,9 @@ extern "C" {
RPY_EXTERN
int cppyy_is_enum(const char* type_name);
+ RPY_EXTERN
+ const char** cppyy_get_all_cpp_names(cppyy_scope_t scope, size_t* count);
+
/* class reflection information ------------------------------------------- */
RPY_EXTERN
char* cppyy_final_name(cppyy_type_t type);
@@ -105,6 +116,10 @@ extern "C" {
char* cppyy_base_name(cppyy_type_t type, int base_index);
RPY_EXTERN
int cppyy_is_subtype(cppyy_type_t derived, cppyy_type_t base);
+ RPY_EXTERN
+ int cppyy_smartptr_info(const char* name, cppyy_type_t* raw, cppyy_method_t* deref);
+ RPY_EXTERN
+ void cppyy_add_smartptr_type(const char* type_name);
/* calculate offsets between declared and actual type, up-cast: direction > 0; down-cast: direction < 0 */
RPY_EXTERN
@@ -114,8 +129,6 @@ extern "C" {
RPY_EXTERN
int cppyy_num_methods(cppyy_scope_t scope);
RPY_EXTERN
- cppyy_index_t cppyy_method_index_at(cppyy_scope_t scope, int imeth);
- RPY_EXTERN
cppyy_index_t* cppyy_method_indices_from_name(cppyy_scope_t scope, const char* name);
RPY_EXTERN
@@ -136,8 +149,12 @@ extern "C" {
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_is_const_method(cppyy_method_t);
RPY_EXTERN
+ int cppyy_exists_method_template(cppyy_scope_t scope, const char* name);
+ RPY_EXTERN
int cppyy_method_is_template(cppyy_scope_t scope, cppyy_index_t idx);
RPY_EXTERN
int cppyy_method_num_template_args(cppyy_scope_t scope, cppyy_index_t idx);
@@ -169,15 +186,20 @@ extern "C" {
char* cppyy_datamember_type(cppyy_scope_t scope, int datamember_index);
RPY_EXTERN
ptrdiff_t cppyy_datamember_offset(cppyy_scope_t scope, int datamember_index);
-
RPY_EXTERN
int cppyy_datamember_index(cppyy_scope_t scope, const char* name);
/* data member properties ------------------------------------------------- */
RPY_EXTERN
- int cppyy_is_publicdata(cppyy_type_t type, int datamember_index);
+ int cppyy_is_publicdata(cppyy_type_t type, cppyy_index_t datamember_index);
+ RPY_EXTERN
+ int cppyy_is_staticdata(cppyy_type_t type, cppyy_index_t datamember_index);
+ RPY_EXTERN
+ int cppyy_is_const_data(cppyy_scope_t scope, cppyy_index_t idata);
+ RPY_EXTERN
+ int cppyy_is_enum_data(cppyy_scope_t scope, cppyy_index_t idata);
RPY_EXTERN
- int cppyy_is_staticdata(cppyy_type_t type, int datamember_index);
+ int cppyy_get_dimension_size(cppyy_scope_t scope, cppyy_index_t idata, int dimension);
/* misc helpers ----------------------------------------------------------- */
RPY_EXTERN
@@ -197,7 +219,7 @@ extern "C" {
RPY_EXTERN
const char* cppyy_stdvector_valuetype(const char* clname);
RPY_EXTERN
- size_t cppyy_stdvector_valuesize(const char* clname);
+ size_t cppyy_stdvector_valuesize(const char* clname);
#ifdef __cplusplus
}
diff --git a/pypy/module/_cppyy/interp_cppyy.py b/pypy/module/_cppyy/interp_cppyy.py
index 063498a0e6..53ae1ea788 100644
--- a/pypy/module/_cppyy/interp_cppyy.py
+++ b/pypy/module/_cppyy/interp_cppyy.py
@@ -19,6 +19,9 @@ INSTANCE_FLAGS_PYTHON_OWNS = 0x0001
INSTANCE_FLAGS_IS_REF = 0x0002
INSTANCE_FLAGS_IS_R_VALUE = 0x0004
+OVERLOAD_FLAGS_USE_FFI = 0x0001
+
+
class FastCallNotPossible(Exception):
pass
@@ -174,7 +177,7 @@ class CPPMethod(object):
@staticmethod
def unpack_cppthis(space, w_cppinstance, declaring_scope):
- cppinstance = space.interp_w(W_CPPClass, w_cppinstance, can_be_None=False)
+ cppinstance = space.interp_w(W_CPPInstance, w_cppinstance, can_be_None=False)
cppinstance._nullcheck()
return cppinstance.get_cppthis(declaring_scope)
@@ -186,7 +189,7 @@ class CPPMethod(object):
return rffi.cast(rffi.VOIDP, loc_idx)
@jit.unroll_safe
- def call(self, cppthis, args_w):
+ def call(self, cppthis, args_w, useffi):
jit.promote(self)
assert lltype.typeOf(cppthis) == capi.C_OBJECT
@@ -218,16 +221,23 @@ class CPPMethod(object):
try:
# attempt to call directly through ffi chain
- if self._funcaddr:
+ if useffi and self._funcaddr:
try:
return self.do_fast_call(cppthis, args_w, call_local)
except FastCallNotPossible:
pass # can happen if converters or executor does not implement ffi
# ffi chain must have failed; using stub functions instead
- args = self.prepare_arguments(args_w, call_local)
+ args, stat = self.prepare_arguments(args_w, call_local)
try:
- return self.executor.execute(self.space, self.cppmethod, cppthis, len(args_w), args)
+ result = self.executor.execute(
+ self.space, self.cppmethod, cppthis, len(args_w), args)
+ if stat[0] != rffi.cast(rffi.ULONG, 0):
+ what = rffi.cast(rffi.CCHARP, stat[1])
+ pywhat = rffi.charp2str(what)
+ capi.c_free(self.space, rffi.cast(rffi.VOIDP, what))
+ raise OperationError(self.space.w_Exception, self.space.newtext(pywhat))
+ return result
finally:
self.finalize_call(args, args_w, call_local)
finally:
@@ -322,7 +332,7 @@ class CPPMethod(object):
# Each CPPMethod corresponds one-to-one to a C++ equivalent and cppthis
# has been offset to the matching class. Hence, the libffi pointer is
# uniquely defined and needs to be setup only once.
- funcaddr = capi.c_get_function_address(self.space, self.scope, self.index)
+ funcaddr = capi.c_function_address_from_index(self.space, self.scope, self.index)
if funcaddr and cppthis: # methods only for now
state = self.space.fromcache(ffitypes.State)
@@ -373,7 +383,10 @@ class CPPMethod(object):
conv.free_argument(self.space, rffi.cast(capi.C_OBJECT, arg_j), loc_j)
capi.c_deallocate_function_args(self.space, args)
raise
- return args
+ stat = rffi.cast(rffi.ULONGP,
+ lltype.direct_ptradd(rffi.cast(rffi.CCHARP, args), int(len(args_w))*stride))
+ stat[0] = rffi.cast(rffi.ULONG, 0)
+ return args, stat
@jit.unroll_safe
def finalize_call(self, args, args_w, call_local):
@@ -435,7 +448,7 @@ class CPPTemplatedCall(CPPMethod):
# TODO: might have to specialize for CPPTemplatedCall on CPPMethod/CPPFunction here
CPPMethod.__init__(self, space, declaring_scope, method_index, arg_defs, args_required)
- def call(self, cppthis, args_w):
+ def call(self, cppthis, args_w, useffi):
assert lltype.typeOf(cppthis) == capi.C_OBJECT
for i in range(len(args_w)):
try:
@@ -447,10 +460,10 @@ class CPPTemplatedCall(CPPMethod):
raise oefmt(self.space.w_TypeError,
"non-matching template (got %s where %s expected)",
s, self.templ_args[i])
- return W_CPPBoundMethod(cppthis, self)
+ return W_CPPBoundMethod(cppthis, self, useffi)
- def bound_call(self, cppthis, args_w):
- return CPPMethod.call(self, cppthis, args_w)
+ def bound_call(self, cppthis, args_w, useffi):
+ return CPPMethod.call(self, cppthis, args_w, useffi)
def __repr__(self):
return "CPPTemplatedCall: %s" % self.prototype()
@@ -468,11 +481,11 @@ class CPPConstructor(CPPMethod):
def unpack_cppthis(space, w_cppinstance, declaring_scope):
return rffi.cast(capi.C_OBJECT, declaring_scope.handle)
- def call(self, cppthis, args_w):
+ def call(self, cppthis, args_w, useffi):
# Note: this does not return a wrapped instance, just a pointer to the
# new instance; the overload must still wrap it before returning. Also,
# cppthis is declaring_scope.handle (as per unpack_cppthis(), above).
- return CPPMethod.call(self, cppthis, args_w)
+ return CPPMethod.call(self, cppthis, args_w, useffi)
def __repr__(self):
return "CPPConstructor: %s" % self.prototype()
@@ -485,7 +498,7 @@ class CPPSetItem(CPPMethod):
_immutable_ = True
- def call(self, cppthis, args_w):
+ def call(self, cppthis, args_w, useffi):
end = len(args_w)-1
if 0 <= end:
w_item = args_w[end]
@@ -493,7 +506,7 @@ class CPPSetItem(CPPMethod):
if self.converters is None:
self._setup(cppthis)
self.executor.set_item(self.space, w_item) # TODO: what about threads?
- CPPMethod.call(self, cppthis, args_w)
+ CPPMethod.call(self, cppthis, args_w, useffi)
class W_CPPOverload(W_Root):
@@ -501,7 +514,7 @@ class W_CPPOverload(W_Root):
collection of (possibly) overloaded methods or functions. It calls these
in order and deals with error handling and reporting."""
- _attrs_ = ['space', 'scope', 'functions']
+ _attrs_ = ['space', 'scope', 'functions', 'flags']
_immutable_fields_ = ['scope', 'functions[*]']
def __init__(self, space, declaring_scope, functions):
@@ -510,6 +523,19 @@ class W_CPPOverload(W_Root):
assert len(functions)
from rpython.rlib import debug
self.functions = debug.make_sure_not_resized(functions)
+ self.flags = 0
+ self.flags |= OVERLOAD_FLAGS_USE_FFI
+
+ # allow user to determine ffi use rules per overload
+ def fget_useffi(self, space):
+ return space.newbool(bool(self.flags & OVERLOAD_FLAGS_USE_FFI))
+
+ @unwrap_spec(value=bool)
+ def fset_useffi(self, space, value):
+ if space.is_true(value):
+ self.flags |= OVERLOAD_FLAGS_USE_FFI
+ else:
+ self.flags &= ~OVERLOAD_FLAGS_USE_FFI
@jit.elidable_promote()
def is_static(self):
@@ -540,7 +566,7 @@ class W_CPPOverload(W_Root):
for i in range(len(self.functions)):
cppyyfunc = self.functions[i]
try:
- return cppyyfunc.call(cppthis, args_w)
+ return cppyyfunc.call(cppthis, args_w, self.flags & OVERLOAD_FLAGS_USE_FFI)
except Exception:
pass
@@ -553,7 +579,7 @@ class W_CPPOverload(W_Root):
for i in range(len(self.functions)):
cppyyfunc = self.functions[i]
try:
- return cppyyfunc.call(cppthis, args_w)
+ return cppyyfunc.call(cppthis, args_w, self.flags & OVERLOAD_FLAGS_USE_FFI)
except OperationError as e:
# special case if there's just one function, to prevent clogging the error message
if len(self.functions) == 1:
@@ -588,6 +614,7 @@ W_CPPOverload.typedef = TypeDef(
'CPPOverload',
is_static = interp2app(W_CPPOverload.is_static),
call = interp2app(W_CPPOverload.call),
+ __useffi__ = GetSetProperty(W_CPPOverload.fget_useffi, W_CPPOverload.fset_useffi),
prototype = interp2app(W_CPPOverload.prototype),
)
@@ -611,7 +638,7 @@ class W_CPPConstructorOverload(W_CPPOverload):
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)
+ cppinstance = self.space.interp_w(W_CPPInstance, w_cppinstance, can_be_None=True)
if cppinstance is not None:
cppinstance._rawobject = newthis
memory_regulator.register(cppinstance)
@@ -642,17 +669,18 @@ W_CPPTemplateOverload.typedef = TypeDef(
class W_CPPBoundMethod(W_Root):
- _attrs_ = ['cppthis', 'method']
+ _attrs_ = ['cppthis', 'method', 'useffi']
- def __init__(self, cppthis, method):
+ def __init__(self, cppthis, method, useffi):
self.cppthis = cppthis
self.method = method
+ self.useffi = useffi
def __call__(self, args_w):
- return self.method.bound_call(self.cppthis, args_w)
+ return self.method.bound_call(self.cppthis, args_w, self.useffi)
def __repr__(self):
- return "W_CPPBoundMethod(%s)" % [f.prototype() for f in self.functions]
+ return "W_CPPBoundMethod(%s)" % self.method.prototype()
W_CPPBoundMethod.typedef = TypeDef(
'CPPBoundMethod',
@@ -682,7 +710,7 @@ class W_CPPDataMember(W_Root):
return offset
def get(self, w_cppinstance, w_pycppclass):
- cppinstance = self.space.interp_w(W_CPPClass, w_cppinstance, can_be_None=True)
+ cppinstance = self.space.interp_w(W_CPPInstance, w_cppinstance, can_be_None=True)
if not cppinstance:
raise oefmt(self.space.w_AttributeError,
"attribute access requires an instance")
@@ -690,7 +718,7 @@ class W_CPPDataMember(W_Root):
return self.converter.from_memory(self.space, w_cppinstance, w_pycppclass, offset)
def set(self, w_cppinstance, w_value):
- cppinstance = self.space.interp_w(W_CPPClass, w_cppinstance, can_be_None=True)
+ cppinstance = self.space.interp_w(W_CPPInstance, w_cppinstance, can_be_None=True)
if not cppinstance:
raise oefmt(self.space.w_AttributeError,
"attribute access requires an instance")
@@ -845,24 +873,11 @@ class W_CPPNamespaceDecl(W_CPPScopeDecl):
return self.space.w_True
def ns__dir__(self):
- # Collect a list of everything (currently) available in the namespace.
- # The backend can filter by returning empty strings. Special care is
- # taken for functions, which need not be unique (overloading).
- alldir = []
- for i in range(capi.c_num_scopes(self.space, self)):
- sname = capi.c_scope_name(self.space, self, i)
- if sname: alldir.append(self.space.newtext(sname))
- allmeth = {}
- for i in range(capi.c_num_methods(self.space, self)):
- idx = capi.c_method_index_at(self.space, self, i)
- mname = capi.c_method_name(self.space, self, idx)
- if mname: allmeth.setdefault(mname, 0)
- for m in allmeth.keys():
- alldir.append(self.space.newtext(m))
- for i in range(capi.c_num_datamembers(self.space, self)):
- dname = capi.c_datamember_name(self.space, self, i)
- if dname: alldir.append(self.space.newtext(dname))
- return self.space.newlist(alldir)
+ alldir = capi.c_get_all_cpp_names(self.space, self)
+ w_alldir = self.space.newlist([])
+ for name in alldir:
+ w_alldir.append(self.space.newtext(name))
+ return w_alldir
def missing_attribute_error(self, name):
return oefmt(self.space.w_AttributeError,
@@ -890,8 +905,7 @@ class W_CPPClassDecl(W_CPPScopeDecl):
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)
+ for idx in range(capi.c_num_methods(self.space, self)):
if capi.c_is_constructor(self.space, self, idx):
pyname = '__init__'
else:
@@ -1029,7 +1043,7 @@ W_CPPComplexClassDecl.typedef = TypeDef(
W_CPPComplexClassDecl.typedef.acceptable_as_base_class = False
-class W_CPPClass(W_Root):
+class W_CPPInstance(W_Root):
_attrs_ = ['space', 'clsdecl', '_rawobject', 'flags',
'finalizer_registered']
_immutable_fields_ = ['clsdecl']
@@ -1109,8 +1123,8 @@ class W_CPPClass(W_Root):
# find a global overload in gbl, in __gnu_cxx (for iterators), or in the
# scopes of the argument classes (TODO: implement that last option)
try:
- # TODO: expecting w_other to be an W_CPPClass is too limiting
- other = self.space.interp_w(W_CPPClass, w_other, can_be_None=False)
+ # TODO: expecting w_other to be an W_CPPInstance is too limiting
+ other = self.space.interp_w(W_CPPInstance, w_other, can_be_None=False)
for name in ["", "__gnu_cxx", "__1"]:
nss = scope_byname(self.space, name)
meth_idx = capi.c_get_global_operator(
@@ -1132,7 +1146,7 @@ class W_CPPClass(W_Root):
# 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
+ other = self.space.interp_w(W_CPPInstance, w_other, can_be_None=False) # TODO: factor out
iseq = (self._rawobject == other._rawobject) and (self.clsdecl == other.clsdecl)
return self.space.newbool(iseq)
@@ -1176,19 +1190,19 @@ class W_CPPClass(W_Root):
if self.flags & INSTANCE_FLAGS_PYTHON_OWNS:
self.destruct()
-W_CPPClass.typedef = TypeDef(
- 'CPPClass',
- __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__),
- __nonzero__ = interp2app(W_CPPClass.instance__nonzero__),
- __len__ = interp2app(W_CPPClass.instance__len__),
- __cmp__ = interp2app(W_CPPClass.instance__cmp__),
- __repr__ = interp2app(W_CPPClass.instance__repr__),
- __destruct__ = interp2app(W_CPPClass.destruct),
+W_CPPInstance.typedef = TypeDef(
+ 'CPPInstance',
+ __python_owns__ = GetSetProperty(W_CPPInstance.fget_python_owns, W_CPPInstance.fset_python_owns),
+ __init__ = interp2app(W_CPPInstance.instance__init__),
+ __eq__ = interp2app(W_CPPInstance.instance__eq__),
+ __ne__ = interp2app(W_CPPInstance.instance__ne__),
+ __nonzero__ = interp2app(W_CPPInstance.instance__nonzero__),
+ __len__ = interp2app(W_CPPInstance.instance__len__),
+ __cmp__ = interp2app(W_CPPInstance.instance__cmp__),
+ __repr__ = interp2app(W_CPPInstance.instance__repr__),
+ __destruct__ = interp2app(W_CPPInstance.destruct),
)
-W_CPPClass.typedef.acceptable_as_base_class = True
+W_CPPInstance.typedef.acceptable_as_base_class = True
class MemoryRegulator:
@@ -1200,7 +1214,7 @@ class MemoryRegulator:
# Note that for now, the associated test carries an m_padding to make
# a difference in the addresses.
def __init__(self):
- self.objects = rweakref.RWeakValueDictionary(int, W_CPPClass)
+ self.objects = rweakref.RWeakValueDictionary(int, W_CPPInstance)
def register(self, obj):
if not obj._rawobject:
@@ -1266,8 +1280,8 @@ def wrap_cppinstance(space, rawobject, 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)
+ w_cppinstance = space.allocate_instance(W_CPPInstance, w_pycppclass)
+ cppinstance = space.interp_w(W_CPPInstance, w_cppinstance, can_be_None=False)
cppinstance.__init__(space, clsdecl, rawobject, is_ref, python_owns)
memory_regulator.register(cppinstance)
return w_cppinstance
@@ -1311,7 +1325,7 @@ def bind_object(space, w_obj, w_pycppclass, owns=False, cast=False):
def move(space, w_obj):
"""Casts the given instance into an C++-style rvalue."""
- obj = space.interp_w(W_CPPClass, w_obj, can_be_None=True)
+ obj = space.interp_w(W_CPPInstance, w_obj, can_be_None=True)
if obj:
obj.flags |= INSTANCE_FLAGS_IS_R_VALUE
return w_obj
diff --git a/pypy/module/_cppyy/pythonify.py b/pypy/module/_cppyy/pythonify.py
index 77c2dda55b..9b37215ce2 100644
--- a/pypy/module/_cppyy/pythonify.py
+++ b/pypy/module/_cppyy/pythonify.py
@@ -7,7 +7,7 @@ import sys
# Metaclasses are needed to store C++ static data members as properties. Since
# the interp-level does not support metaclasses, they are created at app-level.
# These are the metaclass base classes:
-class CPPMetaScope(type):
+class CPPScope(type):
def __getattr__(self, name):
try:
return get_scoped_pycppitem(self, name) # will cache on self
@@ -15,11 +15,11 @@ class CPPMetaScope(type):
raise AttributeError("%s object has no attribute '%s' (details: %s)" %
(self, name, str(e)))
-class CPPMetaNamespace(CPPMetaScope):
+class CPPMetaNamespace(CPPScope):
def __dir__(self):
return self.__cppdecl__.__dir__()
-class CPPMetaClass(CPPMetaScope):
+class CPPClass(CPPScope):
pass
# namespace base class (class base class defined in _init_pythonify)
@@ -173,7 +173,7 @@ def make_cppclass(scope, cl_name, decl):
# get a list of base classes for class creation
bases = [get_pycppclass(base) for base in decl.get_base_names()]
if not bases:
- bases = [CPPClass,]
+ bases = [CPPInstance,]
else:
# it's possible that the required class now has been built if one of
# the base classes uses it in e.g. a function interface
@@ -214,7 +214,7 @@ def make_cppclass(scope, cl_name, decl):
# create a metaclass to allow properties (for static data write access)
metabases = [type(base) for base in bases]
- metacpp = type(CPPMetaScope)(cl_name+'_meta', _drop_cycles(metabases), d_meta)
+ metacpp = type(CPPScope)(cl_name+'_meta', _drop_cycles(metabases), d_meta)
# create the python-side C++ class
pycls = metacpp(cl_name, _drop_cycles(bases), d_class)
@@ -412,11 +412,11 @@ def _init_pythonify():
# at pypy-c startup, rather than on the "import _cppyy" statement
import _cppyy
- # root of all proxy classes: CPPClass in pythonify exists to combine the
- # CPPMetaScope metaclass with the interp-level CPPClassBase
- global CPPClass
- class CPPClass(_cppyy.CPPClassBase):
- __metaclass__ = CPPMetaScope
+ # root of all proxy classes: CPPInstance in pythonify exists to combine
+ # the CPPScope metaclass with the interp-level CPPInstanceBase
+ global CPPInstance
+ class CPPInstance(_cppyy.CPPInstanceBase):
+ __metaclass__ = CPPScope
pass
# class generator callback
@@ -438,9 +438,8 @@ def _init_pythonify():
gbl.std.move = _cppyy.move
# install a type for enums to refer to
- # TODO: this is correct for C++98, not for C++11 and in general there will
- # be the same issue for all typedef'd builtin types
setattr(gbl, 'internal_enum_type_t', int)
+ setattr(gbl, 'unsigned int', int) # if resolved
# install for user access
_cppyy.gbl = gbl
diff --git a/pypy/module/_cppyy/src/dummy_backend.cxx b/pypy/module/_cppyy/src/dummy_backend.cxx
index 6d1f0a51aa..b82dc7b30d 100644
--- a/pypy/module/_cppyy/src/dummy_backend.cxx
+++ b/pypy/module/_cppyy/src/dummy_backend.cxx
@@ -407,11 +407,9 @@ static inline char* cppstring_to_cstring(const std::string& name) {
/* name to opaque C++ scope representation -------------------------------- */
-int cppyy_num_scopes(cppyy_scope_t handle) {
- return 0;
-}
-
char* cppyy_resolve_name(const char* cppitem_name) {
+ if (cppyy_is_enum(cppitem_name))
+ return cppstring_to_cstring("internal_enum_type_t");
return cppstring_to_cstring(cppitem_name);
}
@@ -851,10 +849,13 @@ cppyy_object_t cppyy_constructor(cppyy_method_t method, cppyy_type_t handle, int
return (cppyy_object_t)result;
}
-cppyy_funcaddr_t cppyy_get_function_address(cppyy_scope_t /* scope */, cppyy_index_t /* idx */) {
+cppyy_funcaddr_t cppyy_function_address_from_index(cppyy_scope_t /* scope */, cppyy_index_t /* idx */) {
return (cppyy_funcaddr_t)0;
}
+cppyy_funcaddr_t cppyy_function_address_from_method(cppyy_method_t /* method */) {
+ return (cppyy_funcaddr_t)0;
+}
/* handling of function argument buffer ----------------------------------- */
void* cppyy_allocate_function_args(int nargs) {
@@ -926,10 +927,6 @@ int cppyy_num_methods(cppyy_scope_t handle) {
return s_scopes[handle].m_methods.size();
}
-cppyy_index_t cppyy_method_index_at(cppyy_scope_t /* scope */, int imeth) {
- return (cppyy_index_t)imeth;
-}
-
char* cppyy_method_name(cppyy_scope_t handle, cppyy_index_t method_index) {
return cppstring_to_cstring(s_scopes[handle].m_methods[(int)method_index].m_name);
}
@@ -978,8 +975,17 @@ cppyy_method_t cppyy_get_method(cppyy_scope_t handle, cppyy_index_t method_index
return (cppyy_method_t)0;
}
+cppyy_index_t cppyy_get_global_operator(cppyy_scope_t /* scope */,
+ cppyy_scope_t /* lc */, cppyy_scope_t /* rc */, const char* /* op */) {
+ return (cppyy_index_t)-1;
+}
+
/* method properties ----------------------------------------------------- */
+int cppyy_is_publicmethod(cppyy_type_t /* handle */, cppyy_index_t /* method_index */) {
+ return 1;
+}
+
int cppyy_is_constructor(cppyy_type_t handle, cppyy_index_t method_index) {
if (s_scopes.find(handle) != s_scopes.end())
return s_scopes[handle].m_methods[method_index].m_type == kConstructor;
@@ -987,6 +993,10 @@ int cppyy_is_constructor(cppyy_type_t handle, cppyy_index_t method_index) {
return 0;
}
+int cppyy_is_destructor(cppyy_type_t /* handle */, cppyy_index_t /* method_index */) {
+ return 0;
+}
+
int cppyy_is_staticmethod(cppyy_type_t handle, cppyy_index_t method_index) {
if (s_scopes.find(handle) != s_scopes.end())
return s_scopes[handle].m_methods[method_index].m_type == kStatic;
@@ -1014,14 +1024,22 @@ ptrdiff_t cppyy_datamember_offset(cppyy_scope_t handle, int idatambr) {
/* data member properties ------------------------------------------------ */
-int cppyy_is_publicdata(cppyy_scope_t handle, int idatambr) {
+int cppyy_is_publicdata(cppyy_scope_t /* handle */, cppyy_index_t /* idatambr */) {
return 1;
}
-int cppyy_is_staticdata(cppyy_scope_t handle, int idatambr) {
+int cppyy_is_staticdata(cppyy_scope_t handle, cppyy_index_t idatambr) {
return s_scopes[handle].m_datambrs[idatambr].m_isstatic;
}
+int cppyy_is_const_data(cppyy_scope_t /* handle */, cppyy_index_t /* idatambr */) {
+ return 0;
+}
+
+int cppyy_is_enum_data(cppyy_scope_t /* handle */, cppyy_index_t /* idatambr */) {
+ return 0;
+}
+
/* misc helpers ----------------------------------------------------------- */
#if defined(_MSC_VER)
diff --git a/pypy/module/_cppyy/test/Makefile b/pypy/module/_cppyy/test/Makefile
index 2c04e91d31..c33340dc0e 100644
--- a/pypy/module/_cppyy/test/Makefile
+++ b/pypy/module/_cppyy/test/Makefile
@@ -14,7 +14,7 @@ all : $(dicts)
HASGENREFLEX:=$(shell command -v genreflex 2> /dev/null)
-cppflags=-std=c++11 -O3 -m64 -fPIC -rdynamic
+cppflags=-std=c++14 -O3 -m64 -fPIC -rdynamic
ifdef HASGENREFLEX
genreflex_flags:=$(shell genreflex --cppflags)
cppflags+=$(genreflex_flags)
diff --git a/pypy/module/_cppyy/test/advancedcpp.cxx b/pypy/module/_cppyy/test/advancedcpp.cxx
index c807d84930..0e39c91f83 100644
--- a/pypy/module/_cppyy/test/advancedcpp.cxx
+++ b/pypy/module/_cppyy/test/advancedcpp.cxx
@@ -1,5 +1,7 @@
#include "advancedcpp.h"
+#include <stdexcept>
+
// for testing of default arguments
#define IMPLEMENT_DEFAULTER_CLASS(type, tname) \
@@ -112,3 +114,13 @@ std::string overload_one_way::gime() { return "aap"; }
std::string overload_the_other_way::gime() { return "aap"; }
int overload_the_other_way::gime() const { return 1; }
+
+
+// exception handling testing
+void Thrower::throw_anything() {
+ throw 1;
+}
+
+void Thrower::throw_exception() {
+ throw std::runtime_error("C++ function failed");
+}
diff --git a/pypy/module/_cppyy/test/advancedcpp.h b/pypy/module/_cppyy/test/advancedcpp.h
index e8f3773930..fefe0f0706 100644
--- a/pypy/module/_cppyy/test/advancedcpp.h
+++ b/pypy/module/_cppyy/test/advancedcpp.h
@@ -59,7 +59,7 @@ public:
class a_class { // for esoteric inheritance testing
public:
a_class() { m_a = 1; m_da = 1.1; }
- ~a_class() {}
+ virtual ~a_class() {}
virtual int get_value() = 0;
public:
@@ -221,6 +221,7 @@ double pass_double_through_const_ref(const double& d);
//===========================================================================
class some_abstract_class { // to test abstract class handling
public:
+ virtual ~some_abstract_class() {}
virtual void a_virtual_method() = 0;
};
@@ -399,3 +400,11 @@ public:
std::string gime();
int gime() const;
};
+
+
+//===========================================================================
+class Thrower { // exception handling testing
+public:
+ void throw_anything();
+ void throw_exception();
+};
diff --git a/pypy/module/_cppyy/test/advancedcpp.xml b/pypy/module/_cppyy/test/advancedcpp.xml
index 728668da5e..68a9d2c495 100644
--- a/pypy/module/_cppyy/test/advancedcpp.xml
+++ b/pypy/module/_cppyy/test/advancedcpp.xml
@@ -57,4 +57,6 @@
<class name="overload_one_way" />
<class name="overload_the_other_way" />
+ <class name="Thrower" />
+
</lcgdict>
diff --git a/pypy/module/_cppyy/test/conftest.py b/pypy/module/_cppyy/test/conftest.py
index d562bca27f..05c7940693 100644
--- a/pypy/module/_cppyy/test/conftest.py
+++ b/pypy/module/_cppyy/test/conftest.py
@@ -55,7 +55,7 @@ def pytest_configure(config):
separate_module_files=[srcpath.join('dummy_backend.cxx')],
include_dirs=[incpath, tstpath, cdir],
compile_extra=['-DRPY_EXTERN=RPY_EXPORTED', '-DCPPYY_DUMMY_BACKEND',
- '-fno-strict-aliasing', '-std=c++11'],
+ '-fno-strict-aliasing', '-std=c++14'],
use_cpp_linker=True,
)
@@ -65,7 +65,7 @@ def pytest_configure(config):
outputfilename='libcppyy_dummy_backend',
standalone=False)
except CompilationError as e:
- if '-std=c++11' in str(e):
+ if '-std=c++14' in str(e):
global disabled
disabled = str(e)
return
diff --git a/pypy/module/_cppyy/test/fragile.h b/pypy/module/_cppyy/test/fragile.h
index ee21aa770a..ff857e6c4e 100644
--- a/pypy/module/_cppyy/test/fragile.h
+++ b/pypy/module/_cppyy/test/fragile.h
@@ -30,6 +30,7 @@ public:
void overload(int, no_such_class* p = 0) {}
};
+
static const int dummy_location = 0xdead;
class E {
@@ -105,6 +106,7 @@ public:
class M {
public:
+ virtual ~M() {}
enum E1 { kOnce=42 };
enum E2 { kTwice=12 };
};
diff --git a/pypy/module/_cppyy/test/test_advancedcpp.py b/pypy/module/_cppyy/test/test_advancedcpp.py
index 760523e220..54a5eea1ec 100644
--- a/pypy/module/_cppyy/test/test_advancedcpp.py
+++ b/pypy/module/_cppyy/test/test_advancedcpp.py
@@ -656,3 +656,22 @@ class AppTestADVANCEDCPP:
# TODO: currently fails b/c double** not understood as &double*
#assert cppyy.gbl.my_global_ptr[0] == 1234.
+ def test22_exceptions(self):
+ """Catching of C++ exceptions"""
+
+ import _cppyy as cppyy
+ Thrower = cppyy.gbl.Thrower
+
+ # TODO: clean up this interface:
+ Thrower.__cppdecl__.get_overload('throw_anything').__useffi__ = False
+ Thrower.__cppdecl__.get_overload('throw_exception').__useffi__ = False
+
+ t = Thrower()
+
+ assert raises(Exception, t.throw_anything)
+ assert raises(Exception, t.throw_exception)
+
+ try:
+ t.throw_exception()
+ except Exception, e:
+ "C++ function failed" in str(e)
diff --git a/pypy/module/_cppyy/test/test_overloads.py b/pypy/module/_cppyy/test/test_overloads.py
index bc9f32363d..5048a71463 100644
--- a/pypy/module/_cppyy/test/test_overloads.py
+++ b/pypy/module/_cppyy/test/test_overloads.py
@@ -15,7 +15,6 @@ class AppTestOVERLOADS:
spaceconfig = dict(usemodules=['_cppyy', '_rawffi', 'itertools'])
def setup_class(cls):
- env = os.environ
cls.w_test_dct = cls.space.newtext(test_dct)
cls.w_overloads = cls.space.appexec([], """():
import ctypes
diff --git a/pypy/module/_cppyy/test/test_zjit.py b/pypy/module/_cppyy/test/test_zjit.py
index 4e79f39777..5c6db4c387 100644
--- a/pypy/module/_cppyy/test/test_zjit.py
+++ b/pypy/module/_cppyy/test/test_zjit.py
@@ -137,6 +137,7 @@ class FakeSpace(object):
executor.get_executor(self, 'int').__class__.c_stubcall = staticmethod(c_call_i)
self.w_AttributeError = FakeException(self, "AttributeError")
+ self.w_Exception = FakeException(self, "Exception")
self.w_KeyError = FakeException(self, "KeyError")
self.w_NotImplementedError = FakeException(self, "NotImplementedError")
self.w_ReferenceError = FakeException(self, "ReferenceError")
@@ -282,7 +283,7 @@ class TestFastPathJIT(LLJitMixin):
inst = interp_cppyy._bind_object(space, FakeInt(0), cls, True)
cls.get_overload("__init__").call(inst, [FakeInt(0)])
cppmethod = cls.get_overload(method_name)
- assert isinstance(inst, interp_cppyy.W_CPPClass)
+ assert isinstance(inst, interp_cppyy.W_CPPInstance)
i = 10
while i > 0:
drv.jit_merge_point(inst=inst, cppmethod=cppmethod, i=i)
diff --git a/pypy/module/cpyext/cdatetime.py b/pypy/module/cpyext/cdatetime.py
index ce0bacc004..135f148f08 100644
--- a/pypy/module/cpyext/cdatetime.py
+++ b/pypy/module/cpyext/cdatetime.py
@@ -124,7 +124,7 @@ def init_datetime(space):
# app level datetime.date. If a c-extension class uses datetime.date for its
# base class and defines a tp_dealloc, we will get this:
# c_class->tp_dealloc == tp_dealloc_func
- # c_class->tp_base == datetime.date,
+ # c_class->tp_base == datetime.date,
# datetime.date->tp_dealloc = _PyPy_subtype_dealloc
# datetime.date->tp_base = W_DateTime_Date
# W_DateTime_Date->tp_dealloc = _PyPy_subtype_dealloc
diff --git a/pypy/module/cpyext/test/test_datetime.py b/pypy/module/cpyext/test/test_datetime.py
index cad152e5f2..5f494d9221 100644
--- a/pypy/module/cpyext/test/test_datetime.py
+++ b/pypy/module/cpyext/test/test_datetime.py
@@ -1,3 +1,5 @@
+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 *
@@ -82,6 +84,14 @@ class TestDatetime(BaseApiTest):
date = datetime.datetime.fromtimestamp(0)
assert space.unwrap(space.str(w_date)) == str(date)
+ @pytest.mark.parametrize('name', ['Time', 'DateTime', 'Date', 'Delta'])
+ def test_basicsize(self, space, name):
+ datetime = _PyDateTime_Import(space)
+ py_size = getattr(datetime, "c_%sType" % name).c_tp_basicsize
+ c_size = rffi.sizeof(cts.gettype("PyDateTime_%s" % name))
+ assert py_size == c_size
+
+
class AppTestDatetime(AppTestCpythonExtensionBase):
def test_CAPI(self):
module = self.import_extension('foo', [
@@ -271,9 +281,9 @@ class AppTestDatetime(AppTestCpythonExtensionBase):
6, 6, 6, 6, args, PyDateTimeAPI->TimeType);
"""),
("datetime_with_tzinfo", "METH_O",
- """
+ """
PyObject * obj;
- int tzrefcnt = args->ob_refcnt;
+ int tzrefcnt = args->ob_refcnt;
PyDateTime_IMPORT;
obj = PyDateTimeAPI->DateTime_FromDateAndTime(
2000, 6, 6, 6, 6, 6, 6, args,
@@ -291,7 +301,7 @@ class AppTestDatetime(AppTestCpythonExtensionBase):
return NULL;
}
return obj;
-
+
"""),
], prologue='#include "datetime.h"\n')
from datetime import tzinfo, datetime, timedelta, time
@@ -339,4 +349,4 @@ class AppTestDatetime(AppTestCpythonExtensionBase):
assert module.checks(o) == (True,) * 3 + (False,) * 7 # isinstance(datetime, date)
o = tzinfo()
assert module.checks(o) == (False,) * 8 + (True,) * 2
-
+
diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py
index 4186b7cef9..582f4d6452 100644
--- a/pypy/objspace/std/listobject.py
+++ b/pypy/objspace/std/listobject.py
@@ -968,6 +968,14 @@ class EmptyListStrategy(ListStrategy):
def setslice(self, w_list, start, step, slicelength, w_other):
strategy = w_other.strategy
+ if step != 1:
+ len2 = strategy.length(w_other)
+ if len2 == 0:
+ return
+ else:
+ raise oefmt(self.space.w_ValueError,
+ "attempt to assign sequence of size %d to extended "
+ "slice of size %d", len2, 0)
storage = strategy.getstorage_copy(w_other)
w_list.strategy = strategy
w_list.lstorage = storage
diff --git a/pypy/objspace/std/test/test_listobject.py b/pypy/objspace/std/test/test_listobject.py
index fac306de1a..6c6f576965 100644
--- a/pypy/objspace/std/test/test_listobject.py
+++ b/pypy/objspace/std/test/test_listobject.py
@@ -1078,6 +1078,15 @@ class AppTestListObject(object):
l[::3] = ('a', 'b')
assert l == ['a', 1.1, 2.2, 'b', 4.4, 5.5]
+ l_int = [5]; l_int.pop() # IntListStrategy
+ l_empty = [] # EmptyListStrategy
+ raises(ValueError, "l_int[::-1] = [42]")
+ raises(ValueError, "l_int[::7] = [42]")
+ raises(ValueError, "l_empty[::-1] = [42]")
+ raises(ValueError, "l_empty[::7] = [42]")
+ l_int[::1] = [42]; assert l_int == [42]
+ l_empty[::1] = [42]; assert l_empty == [42]
+
def test_setslice_with_self(self):
l = [1,2,3,4]
l[:] = l