Author: Carl Friedrich Bolz <cfb...@gmx.de> Branch: space-newtext Changeset: r88080:ee5ad76cdf97 Date: 2016-11-02 14:11 +0100 http://bitbucket.org/pypy/pypy/changeset/ee5ad76cdf97/
Log: merge default diff too long, truncating to 2000 out of 3090 lines diff --git a/lib-python/2.7/test/test_ssl.py b/lib-python/2.7/test/test_ssl.py --- a/lib-python/2.7/test/test_ssl.py +++ b/lib-python/2.7/test/test_ssl.py @@ -26,6 +26,8 @@ PROTOCOLS = sorted(ssl._PROTOCOL_NAMES) HOST = support.HOST +IS_LIBRESSL = ssl.OPENSSL_VERSION.startswith('LibreSSL') +IS_OPENSSL_1_1 = not IS_LIBRESSL and ssl.OPENSSL_VERSION_INFO >= (1, 1, 0) def data_file(*name): return os.path.join(os.path.dirname(__file__), *name) @@ -742,15 +744,15 @@ def test_options(self): ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) # OP_ALL | OP_NO_SSLv2 | OP_NO_SSLv3 is the default value - self.assertEqual(ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3, - ctx.options) + default = (ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3) + if not IS_LIBRESSL and ssl.OPENSSL_VERSION_INFO >= (1, 1, 0): + default |= ssl.OP_NO_COMPRESSION + self.assertEqual(default, ctx.options) ctx.options |= ssl.OP_NO_TLSv1 - self.assertEqual(ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 | ssl.OP_NO_TLSv1, - ctx.options) + self.assertEqual(default | ssl.OP_NO_TLSv1, ctx.options) if can_clear_options(): - ctx.options = (ctx.options & ~ssl.OP_NO_SSLv2) | ssl.OP_NO_TLSv1 - self.assertEqual(ssl.OP_ALL | ssl.OP_NO_TLSv1 | ssl.OP_NO_SSLv3, - ctx.options) + ctx.options = (ctx.options & ~ssl.OP_NO_TLSv1) + self.assertEqual(default, ctx.options) ctx.options = 0 self.assertEqual(0, ctx.options) else: @@ -2918,18 +2920,27 @@ client_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) client_context.load_cert_chain(CERTFILE) client_context.set_alpn_protocols(client_protocols) - stats = server_params_test(client_context, server_context, - chatty=True, connectionchatty=True) - - msg = "failed trying %s (s) and %s (c).\n" \ - "was expecting %s, but got %%s from the %%s" \ - % (str(server_protocols), str(client_protocols), - str(expected)) - client_result = stats['client_alpn_protocol'] - self.assertEqual(client_result, expected, msg % (client_result, "client")) - server_result = stats['server_alpn_protocols'][-1] \ - if len(stats['server_alpn_protocols']) else 'nothing' - self.assertEqual(server_result, expected, msg % (server_result, "server")) + try: + stats = server_params_test(client_context, server_context, + chatty=True, connectionchatty=True) + except ssl.SSLError as e: + stats = e + + if expected is None and IS_OPENSSL_1_1: + # OpenSSL 1.1.0 raises handshake error + self.assertIsInstance(stats, ssl.SSLError) + else: + msg = "failed trying %s (s) and %s (c).\n" \ + "was expecting %s, but got %%s from the %%s" \ + % (str(server_protocols), str(client_protocols), + str(expected)) + client_result = stats['client_alpn_protocol'] + self.assertEqual(client_result, expected, + msg % (client_result, "client")) + server_result = stats['server_alpn_protocols'][-1] \ + if len(stats['server_alpn_protocols']) else 'nothing' + self.assertEqual(server_result, expected, + msg % (server_result, "server")) def test_selected_npn_protocol(self): # selected_npn_protocol() is None unless NPN is used diff --git a/lib_pypy/_collections.py b/lib_pypy/_collections.py --- a/lib_pypy/_collections.py +++ b/lib_pypy/_collections.py @@ -29,7 +29,7 @@ class deque(object): def __new__(cls, iterable=(), *args, **kw): - self = super(deque, cls).__new__(cls, *args, **kw) + self = super(deque, cls).__new__(cls) self.clear() return self 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 @@ -229,7 +229,7 @@ __metaclass__ = StructOrUnionMeta def __new__(cls, *args, **kwds): - self = super(_CData, cls).__new__(cls, *args, **kwds) + self = super(_CData, cls).__new__(cls) if '_abstract_' in cls.__dict__: raise TypeError("abstract class") if hasattr(cls, '_ffistruct_'): diff --git a/lib_pypy/cffi.egg-info/PKG-INFO b/lib_pypy/cffi.egg-info/PKG-INFO --- a/lib_pypy/cffi.egg-info/PKG-INFO +++ b/lib_pypy/cffi.egg-info/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: cffi -Version: 1.8.4 +Version: 1.9.0 Summary: Foreign Function Interface for Python calling C code. Home-page: http://cffi.readthedocs.org Author: Armin Rigo, Maciej Fijalkowski diff --git a/lib_pypy/cffi/__init__.py b/lib_pypy/cffi/__init__.py --- a/lib_pypy/cffi/__init__.py +++ b/lib_pypy/cffi/__init__.py @@ -4,8 +4,8 @@ from .api import FFI, CDefError, FFIError from .ffiplatform import VerificationError, VerificationMissing -__version__ = "1.8.4" -__version_info__ = (1, 8, 4) +__version__ = "1.9.0" +__version_info__ = (1, 9, 0) # The verifier module file names are based on the CRC32 of a string that # contains the following version number. It may be older than __version__ diff --git a/lib_pypy/cffi/_embedding.h b/lib_pypy/cffi/_embedding.h --- a/lib_pypy/cffi/_embedding.h +++ b/lib_pypy/cffi/_embedding.h @@ -233,7 +233,7 @@ f = PySys_GetObject((char *)"stderr"); if (f != NULL && f != Py_None) { PyFile_WriteString("\nFrom: " _CFFI_MODULE_NAME - "\ncompiled with cffi version: 1.8.4" + "\ncompiled with cffi version: 1.9.0" "\n_cffi_backend module: ", f); modules = PyImport_GetModuleDict(); mod = PyDict_GetItemString(modules, "_cffi_backend"); diff --git a/lib_pypy/cffi/cparser.py b/lib_pypy/cffi/cparser.py --- a/lib_pypy/cffi/cparser.py +++ b/lib_pypy/cffi/cparser.py @@ -334,6 +334,8 @@ realtype, quals = self._get_type_and_quals( decl.type, name=decl.name, partial_length_ok=True) self._declare('typedef ' + decl.name, realtype, quals=quals) + elif decl.__class__.__name__ == 'Pragma': + pass # skip pragma, only in pycparser 2.15 else: raise api.CDefError("unrecognized construct", decl) except api.FFIError as e: diff --git a/lib_pypy/cffi/model.py b/lib_pypy/cffi/model.py --- a/lib_pypy/cffi/model.py +++ b/lib_pypy/cffi/model.py @@ -519,10 +519,18 @@ smallest_value = min(self.enumvalues) largest_value = max(self.enumvalues) else: - raise api.CDefError("%r has no values explicitly defined: " - "refusing to guess which integer type it is " - "meant to be (unsigned/signed, int/long)" - % self._get_c_name()) + import warnings + try: + # XXX! The goal is to ensure that the warnings.warn() + # will not suppress the warning. We want to get it + # several times if we reach this point several times. + __warningregistry__.clear() + except NameError: + pass + warnings.warn("%r has no values explicitly defined; " + "guessing that it is equivalent to 'unsigned int'" + % self._get_c_name()) + smallest_value = largest_value = 0 if smallest_value < 0: # needs a signed type sign = 1 candidate1 = PrimitiveType("int") diff --git a/lib_pypy/cffi/setuptools_ext.py b/lib_pypy/cffi/setuptools_ext.py --- a/lib_pypy/cffi/setuptools_ext.py +++ b/lib_pypy/cffi/setuptools_ext.py @@ -1,4 +1,5 @@ import os +import sys try: basestring @@ -74,8 +75,13 @@ Add py_limited_api to kwds if setuptools >= 26 is in use. Do not alter the setting if it already exists. Setuptools takes care of ignoring the flag on Python 2 and PyPy. + + CPython itself should ignore the flag in a debugging version + (by not listing .abi3.so in the extensions it supports), but + it doesn't so far, creating troubles. That's why we check + for "not sys.flags.debug". (http://bugs.python.org/issue28401) """ - if 'py_limited_api' not in kwds: + if 'py_limited_api' not in kwds and not sys.flags.debug: import setuptools try: setuptools_major_version = int(setuptools.__version__.partition('.')[0]) diff --git a/pypy/doc/faq.rst b/pypy/doc/faq.rst --- a/pypy/doc/faq.rst +++ b/pypy/doc/faq.rst @@ -397,3 +397,13 @@ in auto-generated C code, and at least some knowledge about the various components involved, from PyPy's own RPython source code to the GC and possibly the JIT. + + +Why doesn't PyPy move to GitHub, Gitlab, ...? +---------------------------------------------- + +We've been quite happy with bitbucket.org. Moving version control systems and +hosting is a lot of hard work: On the one hand, PyPy's mercurial history is +long and gnarly. On the other hand, all our infrastructure (buildbots, +benchmarking, etc) would have to be adapted. So unless somebody steps up and +volunteers to do all that work, it will likely not happen. diff --git a/pypy/doc/install.rst b/pypy/doc/install.rst --- a/pypy/doc/install.rst +++ b/pypy/doc/install.rst @@ -1,8 +1,17 @@ Downloading and Installing PyPy =============================== +Using a packaged PyPy +~~~~~~~~~~~~~~~~~~~~~ + +Some Linux distributions provide a pypy package. Note that in order to +install additional modules that require compilation, you may need to install +additional packages such as pypy-dev. This will manifest as an error about +"missing Python.h". Distributions do not as of yet supply many pypy-ready +packages, if you require additional modules we recommend creating a virtualenv +and using pip. + .. _prebuilt-pypy: - Download a pre-built PyPy ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -38,6 +47,9 @@ and not move the binary there, else PyPy would not be able to find its library. +Installing more modules +~~~~~~~~~~~~~~~~~~~~~~~ + If you want to install 3rd party libraries, the most convenient way is to install pip_ using ensurepip_ (unless you want to install virtualenv as explained below; then you can directly use pip inside virtualenvs): diff --git a/pypy/doc/release-pypy2.7-v5.6.0.rst b/pypy/doc/release-pypy2.7-v5.6.0.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/release-pypy2.7-v5.6.0.rst @@ -0,0 +1,147 @@ +============ +PyPy2.7 v5.6 +============ + +We have released PyPy2.7 v5.6, about two months after PyPy2.7 v5.4. +This new PyPy2.7 release includes the upstream stdlib version 2.7.12. + +We continue to make incremental improvements to our C-API +compatability layer (cpyext). We pass all but a few of the tests in the +upstream numpy `test suite`_. + +Work proceeds at a good pace on the PyPy3.5 +version due to a grant_ from the Mozilla Foundation, and some of those +changes have been backported to PyPy2.7 where relevant + +We changed ``timeit`` to now report average +- standard deviation, which is +better than the misleading minimum value reported in CPython. + +We now support building PyPy with OpenSSL 1.1 in our built-in _sll module, as +well as maintaining support for previous versions. + +XXX + +As always, this release fixed many issues and bugs raised by the +growing community of PyPy users. We strongly recommend updating. + +You can download the PyPy2.7 v5.6 release here: + + http://pypy.org/download.html + +We would like to thank our donors for the continued support of the PyPy +project. + +We would also like to thank our contributors and +encourage new people to join the project. PyPy has many +layers and we need help with all of them: `PyPy`_ and `RPython`_ documentation +improvements, tweaking popular `modules`_ to run on pypy, or general `help`_ +with making RPython's JIT even better. + +.. _`test suite`: https://bitbucket.org/pypy/pypy/wiki/Adventures%20in%20cpyext%20compatibility +.. _cffi: https://cffi.readthedocs.org +.. _grant: https://morepypy.blogspot.com/2016/08/pypy-gets-funding-from-mozilla-for.html +.. _`PyPy`: http://doc.pypy.org +.. _`RPython`: https://rpython.readthedocs.org +.. _`modules`: http://doc.pypy.org/en/latest/project-ideas.html#make-more-python-modules-pypy-friendly +.. _`help`: http://doc.pypy.org/en/latest/project-ideas.html + +What is PyPy? +============= + +PyPy is a very compliant Python interpreter, almost a drop-in replacement for +CPython 2.7. It's fast (`PyPy and CPython 2.7.x`_ performance comparison) +due to its integrated tracing JIT compiler. + +We also welcome developers of other `dynamic languages`_ to see what RPython +can do for them. + +This release supports: + + * **x86** machines on most common operating systems + (Linux 32/64 bits, Mac OS X 64 bits, Windows 32 bits, OpenBSD, FreeBSD) + + * newer **ARM** hardware (ARMv6 or ARMv7, with VFPv3) running Linux, + + * big- and little-endian variants of **PPC64** running Linux, + + * **s390x** running Linux + +.. _`PyPy and CPython 2.7.x`: http://speed.pypy.org +.. _`dynamic languages`: http://pypyjs.org + +Other Highlights (since 5.4 released Aug 31, 2016) +========================================================= + +* New features + * Allow tests run with `-A` to find `libm.so` even if it is a script not a + dynamically loadable file + * Backport fixes to rposix on windows from py3.5 + * Allow user-defined ``__getitem__`` on subclasses of ``str`` and ``unicode`` + * Add ``inode`` to ``scandir()`` on posix systems + * Support more attributes on ``super`` + * Issue #2386: non-latin1 unicode keys were ignored in ``unicode.format(**d)`` + * Restore the ability to translate with CPython + * Update to CFFI 1.8.4 + * Support the new buffer protocol in cpyext and numpypy + * Add ``rposix.sync()`` + * Support full-precision nanosecond times in os.stat() + * Add documentation about the assembler backends to RPYthon + * Search for the stdlibs from the libpypy shared object rather than the pypy-c exe, + changes downstream packaging requirments + * Add ``try_inline``, like ``always_inline`` and ``dont_inline`` to RPython + * Reject ``'a'.strip(buffer(' '))`` like cpython (the argument to strip must + be ``str`` or ``unicode``) + * Allow ``warning.warn(('something', 1), Warning)`` like on CPython + * Refactor ``rclock`` and add some more ``CLOCK_xxx`` constants on + relevant platforms + * Backport the ``'faulthandler`` module from py3.5 + * Improve the error message when trying to call a method where the ``self`` + parameter is missing in the definition + * Implement ``rposix.cpu_count`` + * Support translation on FreeBSD running on PowerPC + * Implement ``__rmod__`` on ``str`` and ``unicode`` types + * Issue warnings for stricter handling of ``__new__``, ``__init__`` args + * When using ``struct.unpack('q', ...`` try harder to prefer int to long + * Support OpenSSL version 1.1 (in addition to version 1.0) + +* Bug Fixes + * Tweak a float comparison with 0 in `backendopt.inline` to avoid rounding errors + * Fix translation of the sandbox + * Fix for an issue where `unicode.decode('utf8', 'custom_replace')` messed up + the last byte of a unicode string sometimes + * fix some calls to functions through window's COM interface + * fix minor leak when the C call to socketpair() fails + * make sure (-1.0 + 0j).__hash__(), (-1.0).__hash__() returns -2 + * Fix for an issue where PyBytesResize was called on a fresh pyobj + * Fix bug in codewriter about passing the ``exitswitch`` variable to a call + * Don't crash in ``merge_if_blocks`` if the values are symbolics + * Issue #2325/2361: __class__ assignment between two classes with the same + slots + * Issue #2409: don't leak the file descriptor when doing ``open('some-dir')`` + * Windows fixes around vmprof + * Don't use ``sprintf()`` from inside a signal handler + * Test and fix bug from the ``guard_not_forced_2`` branch, which didn't + save the floating-point register + * ``_numpypy.add.reduce`` returns a scalar now + +* Performance improvements: + * Improve method calls on oldstyle classes + * Clean and refactor code for testing cpyext to allow sharing with py3.5 + * Refactor a building the map of reflected ops in ``_numpypy`` + * Improve merging of virtual states in the JIT in order to avoid jumping to the + preamble + * In JIT residual calls, if the called function starts with a fast-path like + ``if x.foo != 0: return x.foo``, then inline the check before doing the + ``CALL``. + * Ensure ``make_inputargs`` fails properly when given arguments with type + information + * Makes ``optimiseopt`` iterative instead of recursive so it can be reasoned + about more easily and debugging is faster + * Refactor and remove dead code from ``optimizeopt``, ``resume`` + + +.. _resolved: http://doc.pypy.org/en/latest/whatsnew-5.6.0.html + +Please update, and continue to help us make PyPy better. + +Cheers 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 @@ -80,3 +80,20 @@ Improve support for new buffer interface in cpyext, bf_getbuffer on built-in types still missing + +.. branch: fix-struct-unpack-Q + +Improve compatibility with CPython in the ``struct`` module. In particular, +``struct.unpack`` now returns an ``int`` whenever the returned value fits, +while previously it always returned a ``long`` for certains format codes such +as ``Q`` (and also ``I``, ``L`` and ``q`` on 32 bit) + +.. branch: newinitwarn + +Issue warnings for stricter handling of ``__new/init__`` args (that +become TypeErrors in python 3) + +.. branch: openssl-1.1 + +PyPy can now be translated on a machine where the newer OpenSSL 1.1 is +installed. Thanks tumbleweed! diff --git a/pypy/interpreter/error.py b/pypy/interpreter/error.py --- a/pypy/interpreter/error.py +++ b/pypy/interpreter/error.py @@ -72,10 +72,7 @@ exc_typename = str(self.w_type) exc_value = str(w_value) else: - if space.is_w(space.type(self.w_type), space.w_str): - exc_typename = space.str_w(self.w_type) - else: - exc_typename = space.str_w( + exc_typename = space.str_w( space.getattr(self.w_type, space.newtext('__name__'))) if space.is_w(w_value, space.w_None): exc_value = "" diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py --- a/pypy/interpreter/function.py +++ b/pypy/interpreter/function.py @@ -610,7 +610,7 @@ class StaticMethod(W_Root): """The staticmethod objects.""" - _immutable_fields_ = ['w_function'] + _immutable_fields_ = ['w_function?'] def __init__(self, w_function): self.w_function = w_function @@ -621,13 +621,16 @@ def descr_staticmethod__new__(space, w_subtype, w_function): instance = space.allocate_instance(StaticMethod, w_subtype) - instance.__init__(w_function) + instance.__init__(space.w_None) return instance + def descr_init(self, space, w_function): + self.w_function = w_function + class ClassMethod(W_Root): """The classmethod objects.""" - _immutable_fields_ = ['w_function'] + _immutable_fields_ = ['w_function?'] def __init__(self, w_function): self.w_function = w_function @@ -640,9 +643,12 @@ def descr_classmethod__new__(space, w_subtype, w_function): instance = space.allocate_instance(ClassMethod, w_subtype) - instance.__init__(w_function) + instance.__init__(space.w_None) return instance + def descr_init(self, space, w_function): + self.w_function = w_function + class FunctionWithFixedCode(Function): can_change_code = False diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -106,8 +106,10 @@ # So we create a few interp-level subclasses of W_XxxObject, which add # some combination of features. This is done using mapdict. -# we need two subclasses of the app-level type, one to add mapdict, and then one -# to add del to not slow down the GC. +# Note that nowadays, we need not "a few" but only one subclass. It +# adds mapdict, which flexibly allows all features. We handle the +# presence or absence of an app-level '__del__' by calling +# register_finalizer() or not. @specialize.memo() def get_unique_interplevel_subclass(space, cls): @@ -687,15 +689,17 @@ (e.g. C().f()). The instance is ignored except for its class.""", __get__ = interp2app(StaticMethod.descr_staticmethod_get), __new__ = interp2app(StaticMethod.descr_staticmethod__new__.im_func), + __init__=interp2app(StaticMethod.descr_init), __func__= interp_attrproperty_w('w_function', cls=StaticMethod), ) ClassMethod.typedef = TypeDef( 'classmethod', - __new__ = interp2app(ClassMethod.descr_classmethod__new__.im_func), - __get__ = interp2app(ClassMethod.descr_classmethod_get), - __func__= interp_attrproperty_w('w_function', cls=ClassMethod), - __doc__ = """classmethod(function) -> class method + __new__=interp2app(ClassMethod.descr_classmethod__new__.im_func), + __init__=interp2app(ClassMethod.descr_init), + __get__=interp2app(ClassMethod.descr_classmethod_get), + __func__=interp_attrproperty_w('w_function', cls=ClassMethod), + __doc__="""classmethod(function) -> class method Convert a function to be a class method. diff --git a/pypy/module/__builtin__/test/test_descriptor.py b/pypy/module/__builtin__/test/test_descriptor.py --- a/pypy/module/__builtin__/test/test_descriptor.py +++ b/pypy/module/__builtin__/test/test_descriptor.py @@ -20,6 +20,12 @@ x = Static(1) assert isinstance(x, Static) + class C(Static): + def __init__(self, callable): + super(C, self).__init__(callable) + y = C(1) + assert isinstance(y, C) + def test_classmethod(self): class C(object): def f(cls, stuff): @@ -41,8 +47,14 @@ x = Classm(1) assert isinstance(x, Classm) + class C(Classm): + def __init__(self, callable): + super(C, self).__init__(callable) + y = C(1) + assert isinstance(y, C) + def test_property_simple(self): - + class a(object): def _get(self): return 42 def _set(self, value): raise AttributeError @@ -98,7 +110,7 @@ assert message.startswith('super(type, obj): obj must be an instance or subtype of type') def test_super_various(self): - + class A(object): def meth(self, a): return "A(%r)" % a @@ -352,10 +364,10 @@ def test_property_subclass_with_init(self): l = [] - + def x(self): l.append('x') - + class P(property): def __init__(self): property.__init__(self, x) diff --git a/pypy/module/_cffi_backend/__init__.py b/pypy/module/_cffi_backend/__init__.py --- a/pypy/module/_cffi_backend/__init__.py +++ b/pypy/module/_cffi_backend/__init__.py @@ -3,7 +3,7 @@ from rpython.rlib import rdynload, clibffi, entrypoint from rpython.rtyper.lltypesystem import rffi -VERSION = "1.8.4" +VERSION = "1.9.0" FFI_DEFAULT_ABI = clibffi.FFI_DEFAULT_ABI try: diff --git a/pypy/module/_cffi_backend/cbuffer.py b/pypy/module/_cffi_backend/cbuffer.py --- a/pypy/module/_cffi_backend/cbuffer.py +++ b/pypy/module/_cffi_backend/cbuffer.py @@ -2,6 +2,7 @@ from pypy.interpreter.gateway import unwrap_spec, interp2app from pypy.interpreter.typedef import TypeDef, make_weakref_descr from pypy.module._cffi_backend import cdataobj, ctypeptr, ctypearray +from pypy.module._cffi_backend import ctypestruct from pypy.objspace.std.bufferobject import W_Buffer from rpython.rlib.buffer import Buffer @@ -71,7 +72,12 @@ ctype = w_cdata.ctype if isinstance(ctype, ctypeptr.W_CTypePointer): if size < 0: - size = ctype.ctitem.size + structobj = w_cdata.get_structobj() + if (structobj is not None and + isinstance(structobj.ctype, ctypestruct.W_CTypeStructOrUnion)): + size = structobj._sizeof() + if size < 0: + size = ctype.ctitem.size elif isinstance(ctype, ctypearray.W_CTypeArray): if size < 0: size = w_cdata._sizeof() diff --git a/pypy/module/_cffi_backend/cdataobj.py b/pypy/module/_cffi_backend/cdataobj.py --- a/pypy/module/_cffi_backend/cdataobj.py +++ b/pypy/module/_cffi_backend/cdataobj.py @@ -329,7 +329,7 @@ def getattr(self, w_attr): cfield = self.getcfield(w_attr) with self as ptr: - w_res = cfield.read(ptr) + w_res = cfield.read(ptr, self) return w_res def setattr(self, w_attr, w_value): @@ -432,6 +432,9 @@ lst = ct.cdata_dir() return space.newlist([space.wrap(s) for s in lst]) + def get_structobj(self): + return None + class W_CDataMem(W_CData): """This is used only by the results of cffi.cast('int', x) @@ -453,28 +456,36 @@ by newp(). They create and free their own memory according to an allocator.""" - # the 'length' is either >= 0 for arrays, or -1 for pointers. - _attrs_ = ['length'] - _immutable_fields_ = ['length'] + # the 'allocated_length' is >= 0 for arrays; for var-sized + # structures it is the total size in bytes; otherwise it is -1. + _attrs_ = ['allocated_length'] + _immutable_fields_ = ['allocated_length'] def __init__(self, space, cdata, ctype, length=-1): W_CData.__init__(self, space, cdata, ctype) - self.length = length + self.allocated_length = length def _repr_extra(self): return self._repr_extra_owning() def _sizeof(self): ctype = self.ctype - if self.length >= 0: + if self.allocated_length >= 0: from pypy.module._cffi_backend import ctypearray - assert isinstance(ctype, ctypearray.W_CTypeArray) - return self.length * ctype.ctitem.size + if isinstance(ctype, ctypearray.W_CTypeArray): + return self.allocated_length * ctype.ctitem.size + else: + return self.allocated_length # var-sized struct size else: return ctype.size def get_array_length(self): - return self.length + from pypy.module._cffi_backend import ctypearray + assert isinstance(self.ctype, ctypearray.W_CTypeArray) + return self.allocated_length + + def get_structobj(self): + return self class W_CDataNewStd(W_CDataNewOwning): @@ -508,12 +519,19 @@ self.structobj = structobj def _repr_extra(self): - return self._repr_extra_owning() + return self.structobj._repr_extra_owning() def _do_getitem(self, ctype, i): assert i == 0 return self.structobj + def get_structobj(self): + structobj = self.structobj + if isinstance(structobj, W_CDataNewOwning): + return structobj + else: + return None + class W_CDataSliced(W_CData): """Subclass with an explicit length, for slices.""" diff --git a/pypy/module/_cffi_backend/ctypeptr.py b/pypy/module/_cffi_backend/ctypeptr.py --- a/pypy/module/_cffi_backend/ctypeptr.py +++ b/pypy/module/_cffi_backend/ctypeptr.py @@ -211,13 +211,16 @@ # a W_CDataPtrToStruct object which has a strong reference # to a W_CDataNewOwning that really contains the structure. # - if not space.is_w(w_init, space.w_None): - ctitem.force_lazy_struct() - if ctitem._with_var_array: + varsize_length = -1 + ctitem.force_lazy_struct() + if ctitem._with_var_array: + if not space.is_w(w_init, space.w_None): datasize = ctitem.convert_struct_from_object( lltype.nullptr(rffi.CCHARP.TO), w_init, datasize) + varsize_length = datasize # - cdatastruct = allocator.allocate(space, datasize, ctitem) + cdatastruct = allocator.allocate(space, datasize, ctitem, + length=varsize_length) ptr = cdatastruct.unsafe_escaping_ptr() cdata = cdataobj.W_CDataPtrToStructOrUnion(space, ptr, self, cdatastruct) diff --git a/pypy/module/_cffi_backend/ctypestruct.py b/pypy/module/_cffi_backend/ctypestruct.py --- a/pypy/module/_cffi_backend/ctypestruct.py +++ b/pypy/module/_cffi_backend/ctypestruct.py @@ -210,7 +210,7 @@ return W_CField(self.ctype, offset + self.offset, self.bitshift, self.bitsize, self.flags | fflags) - def read(self, cdata): + def read(self, cdata, w_cdata): cdata = rffi.ptradd(cdata, self.offset) if self.bitshift == self.BS_REGULAR: return self.ctype.convert_to_object(cdata) @@ -218,6 +218,14 @@ from pypy.module._cffi_backend import ctypearray ctype = self.ctype assert isinstance(ctype, ctypearray.W_CTypeArray) + structobj = w_cdata.get_structobj() + if structobj is not None: + # variable-length array + size = structobj.allocated_length - self.offset + if size >= 0: + arraylen = size // ctype.ctitem.size + return cdataobj.W_CDataSliced(ctype.space, cdata, ctype, + arraylen) return cdataobj.W_CData(ctype.space, cdata, ctype.ctptr) else: return self.convert_bitfield_to_object(cdata) diff --git a/pypy/module/_cffi_backend/newtype.py b/pypy/module/_cffi_backend/newtype.py --- a/pypy/module/_cffi_backend/newtype.py +++ b/pypy/module/_cffi_backend/newtype.py @@ -353,7 +353,7 @@ if fbitsize < 0: # not a bitfield: common case - if isinstance(ftype, ctypearray.W_CTypeArray) and ftype.length==0: + if isinstance(ftype, ctypearray.W_CTypeArray) and ftype.length<=0: bs_flag = ctypestruct.W_CField.BS_EMPTY_ARRAY else: bs_flag = ctypestruct.W_CField.BS_REGULAR diff --git a/pypy/module/_cffi_backend/test/_backend_test_c.py b/pypy/module/_cffi_backend/test/_backend_test_c.py --- a/pypy/module/_cffi_backend/test/_backend_test_c.py +++ b/pypy/module/_cffi_backend/test/_backend_test_c.py @@ -1,7 +1,7 @@ # ____________________________________________________________ import sys -assert __version__ == "1.8.4", ("This test_c.py file is for testing a version" +assert __version__ == "1.9.0", ("This test_c.py file is for testing a version" " of cffi that differs from the one that we" " get from 'import _cffi_backend'") if sys.version_info < (3,): @@ -3161,17 +3161,19 @@ assert d[1][0] == 'y' assert d[1][1].type is BArray assert d[1][1].offset == size_of_int() - assert d[1][1].bitshift == -1 + assert d[1][1].bitshift == -2 assert d[1][1].bitsize == -1 # p = newp(new_pointer_type(BStruct)) p.x = 42 assert p.x == 42 - assert typeof(p.y) is BIntP + assert typeof(p.y) is BArray + assert len(p.y) == 0 assert p.y == cast(BIntP, p) + 1 # p = newp(new_pointer_type(BStruct), [100]) assert p.x == 100 + assert len(p.y) == 0 # # Tests for # ffi.new("struct_with_var_array *", [field.., [the_array_items..]]) @@ -3186,6 +3188,10 @@ p.y[0] = 200 assert p.y[2] == 0 p.y[2] = 400 + assert len(p.y) == 3 + assert len(p[0].y) == 3 + assert len(buffer(p)) == sizeof(BInt) * 4 + assert sizeof(p[0]) == sizeof(BInt) * 4 plist.append(p) for i in range(20): p = plist[i] @@ -3193,13 +3199,31 @@ assert p.y[0] == 200 assert p.y[1] == i assert p.y[2] == 400 - assert list(p.y[0:3]) == [200, i, 400] + assert list(p.y) == [200, i, 400] # # the following assignment works, as it normally would, for any array field - p.y = [500, 600] - assert list(p.y[0:3]) == [500, 600, 400] + p.y = [501, 601] + assert list(p.y) == [501, 601, 400] + p[0].y = [500, 600] + assert list(p[0].y) == [500, 600, 400] + assert repr(p) == "<cdata 'foo *' owning %d bytes>" % ( + sizeof(BStruct) + 3 * sizeof(BInt),) + assert repr(p[0]) == "<cdata 'foo' owning %d bytes>" % ( + sizeof(BStruct) + 3 * sizeof(BInt),) + assert sizeof(p[0]) == sizeof(BStruct) + 3 * sizeof(BInt) + # + # from a non-owning pointer, we can't get the length + q = cast(new_pointer_type(BStruct), p) + assert q.y[0] == 500 + assert q[0].y[0] == 500 + py.test.raises(TypeError, len, q.y) + py.test.raises(TypeError, len, q[0].y) + assert typeof(q.y) is BIntP + assert typeof(q[0].y) is BIntP + assert sizeof(q[0]) == sizeof(BStruct) # # error cases + py.test.raises(IndexError, "p.y[4]") py.test.raises(TypeError, "p.y = cast(BIntP, 0)") py.test.raises(TypeError, "p.y = 15") py.test.raises(TypeError, "p.y = None") @@ -3264,6 +3288,33 @@ assert p.x[5] == 60 assert p.x[6] == 70 +def test_struct_array_not_aligned(): + # struct a { int x; char y; char z[]; }; + # ends up of size 8, but 'z' is at offset 5 + BChar = new_primitive_type("char") + BInt = new_primitive_type("int") + BCharP = new_pointer_type(BChar) + BArray = new_array_type(BCharP, None) + BStruct = new_struct_type("foo") + complete_struct_or_union(BStruct, [('x', BInt), + ('y', BChar), + ('z', BArray)]) + assert sizeof(BStruct) == 2 * size_of_int() + def offsetof(BType, fieldname): + return typeoffsetof(BType, fieldname)[1] + base = offsetof(BStruct, 'z') + assert base == size_of_int() + 1 + # + p = newp(new_pointer_type(BStruct), {'z': 3}) + assert sizeof(p[0]) == base + 3 + q = newp(new_pointer_type(BStruct), {'z': size_of_int()}) + assert sizeof(q) == size_of_ptr() + assert sizeof(q[0]) == base + size_of_int() + assert len(p.z) == 3 + assert len(p[0].z) == 3 + assert len(q.z) == size_of_int() + assert len(q[0].z) == size_of_int() + def test_ass_slice(): BChar = new_primitive_type("char") BArray = new_array_type(new_pointer_type(BChar), None) diff --git a/pypy/module/_cffi_backend/test/test_recompiler.py b/pypy/module/_cffi_backend/test/test_recompiler.py --- a/pypy/module/_cffi_backend/test/test_recompiler.py +++ b/pypy/module/_cffi_backend/test/test_recompiler.py @@ -408,11 +408,14 @@ 'test_misdeclared_field_1', "struct foo_s { int a[6]; };") assert ffi.sizeof("struct foo_s") == 24 # found by the actual C code - p = ffi.new("struct foo_s *") - # lazily build the fields and boom: - e = raises(ffi.error, getattr, p, "a") - assert str(e.value).startswith("struct foo_s: wrong size for field 'a' " - "(cdef says 20, but C compiler says 24)") + try: + # lazily build the fields and boom: + p = ffi.new("struct foo_s *") + p.a + assert False, "should have raised" + except ffi.error as e: + assert str(e).startswith("struct foo_s: wrong size for field 'a' " + "(cdef says 20, but C compiler says 24)") def test_open_array_in_struct(self): ffi, lib = self.prepare( @@ -420,8 +423,10 @@ 'test_open_array_in_struct', "struct foo_s { int b; int a[]; };") assert ffi.sizeof("struct foo_s") == 4 - p = ffi.new("struct foo_s *", [5, [10, 20, 30]]) + p = ffi.new("struct foo_s *", [5, [10, 20, 30, 40]]) assert p.a[2] == 30 + assert ffi.sizeof(p) == ffi.sizeof("void *") + assert ffi.sizeof(p[0]) == 5 * ffi.sizeof("int") def test_math_sin_type(self): ffi, lib = self.prepare( @@ -954,6 +959,7 @@ "struct foo_s { int x; int a[5][8]; int y; };") assert ffi.sizeof('struct foo_s') == 42 * ffi.sizeof('int') s = ffi.new("struct foo_s *") + assert ffi.typeof(s.a) == ffi.typeof("int[5][8]") assert ffi.sizeof(s.a) == 40 * ffi.sizeof('int') assert s.a[4][7] == 0 raises(IndexError, 's.a[4][8]') @@ -961,6 +967,18 @@ assert ffi.typeof(s.a) == ffi.typeof("int[5][8]") assert ffi.typeof(s.a[0]) == ffi.typeof("int[8]") + def test_struct_array_guess_length_3(self): + ffi, lib = self.prepare( + "struct foo_s { int a[][...]; };", + 'test_struct_array_guess_length_3', + "struct foo_s { int x; int a[5][7]; int y; };") + assert ffi.sizeof('struct foo_s') == 37 * ffi.sizeof('int') + s = ffi.new("struct foo_s *") + assert ffi.typeof(s.a) == ffi.typeof("int[][7]") + assert s.a[4][6] == 0 + raises(IndexError, 's.a[4][7]') + assert ffi.typeof(s.a[0]) == ffi.typeof("int[7]") + def test_global_var_array_2(self): ffi, lib = self.prepare( "int a[...][...];", diff --git a/pypy/module/_hashlib/__init__.py b/pypy/module/_hashlib/__init__.py --- a/pypy/module/_hashlib/__init__.py +++ b/pypy/module/_hashlib/__init__.py @@ -1,5 +1,6 @@ from pypy.interpreter.mixedmodule import MixedModule -from pypy.module._hashlib.interp_hashlib import algorithms, fetch_names +from pypy.module._hashlib.interp_hashlib import ( + algorithms, fetch_names, HAS_FAST_PKCS5_PBKDF2_HMAC) class Module(MixedModule): @@ -13,6 +14,9 @@ for name in algorithms: interpleveldefs['openssl_' + name] = 'interp_hashlib.new_' + name + if HAS_FAST_PKCS5_PBKDF2_HMAC: + interpleveldefs['pbkdf2_hmac'] = 'interp_hashlib.pbkdf2_hmac' + def startup(self, space): w_meth_names = fetch_names(space) space.setattr(self, space.wrap('openssl_md_meth_names'), w_meth_names) diff --git a/pypy/module/_hashlib/interp_hashlib.py b/pypy/module/_hashlib/interp_hashlib.py --- a/pypy/module/_hashlib/interp_hashlib.py +++ b/pypy/module/_hashlib/interp_hashlib.py @@ -8,7 +8,7 @@ from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import OperationError, oefmt -from pypy.interpreter.gateway import unwrap_spec, interp2app +from pypy.interpreter.gateway import unwrap_spec, interp2app, WrappedDefault from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.module.thread.os_lock import Lock @@ -58,23 +58,26 @@ def __init__(self, space, name, copy_from=NULL_CTX): self.name = name digest_type = self.digest_type_by_name(space) - self.digest_size = rffi.getintfield(digest_type, 'c_md_size') + self.digest_size = ropenssl.EVP_MD_size(digest_type) # Allocate a lock for each HASH object. # An optimization would be to not release the GIL on small requests, # and use a custom lock only when needed. self.lock = Lock(space) - ctx = lltype.malloc(ropenssl.EVP_MD_CTX.TO, flavor='raw') + ctx = ropenssl.EVP_MD_CTX_new() + if ctx is None: + raise MemoryError rgc.add_memory_pressure(ropenssl.HASH_MALLOC_SIZE + self.digest_size) try: if copy_from: - ropenssl.EVP_MD_CTX_copy(ctx, copy_from) + if not ropenssl.EVP_MD_CTX_copy(ctx, copy_from): + raise ValueError else: ropenssl.EVP_DigestInit(ctx, digest_type) self.ctx = ctx except: - lltype.free(ctx, flavor='raw') + ropenssl.EVP_MD_CTX_free(ctx) raise self.register_finalizer(space) @@ -82,8 +85,7 @@ ctx = self.ctx if ctx: self.ctx = lltype.nullptr(ropenssl.EVP_MD_CTX.TO) - ropenssl.EVP_MD_CTX_cleanup(ctx) - lltype.free(ctx, flavor='raw') + ropenssl.EVP_MD_CTX_free(ctx) def digest_type_by_name(self, space): digest_type = ropenssl.EVP_get_digestbyname(self.name) @@ -128,21 +130,26 @@ def get_block_size(self, space): digest_type = self.digest_type_by_name(space) - block_size = rffi.getintfield(digest_type, 'c_block_size') + block_size = ropenssl.EVP_MD_block_size(digest_type) return space.wrap(block_size) def get_name(self, space): return space.wrap(self.name) def _digest(self, space): - with lltype.scoped_alloc(ropenssl.EVP_MD_CTX.TO) as ctx: + ctx = ropenssl.EVP_MD_CTX_new() + if ctx is None: + raise MemoryError + try: with self.lock: - ropenssl.EVP_MD_CTX_copy(ctx, self.ctx) + if not ropenssl.EVP_MD_CTX_copy(ctx, self.ctx): + raise ValueError digest_size = self.digest_size with rffi.scoped_alloc_buffer(digest_size) as buf: ropenssl.EVP_DigestFinal(ctx, buf.raw, None) - ropenssl.EVP_MD_CTX_cleanup(ctx) return buf.str(digest_size) + finally: + ropenssl.EVP_MD_CTX_free(ctx) W_Hash.typedef = TypeDef( @@ -177,3 +184,27 @@ for _name in algorithms: _newname = 'new_%s' % (_name,) globals()[_newname] = make_new_hash(_name, _newname) + + +HAS_FAST_PKCS5_PBKDF2_HMAC = ropenssl.PKCS5_PBKDF2_HMAC is not None +if HAS_FAST_PKCS5_PBKDF2_HMAC: + @unwrap_spec(name=str, password=str, salt=str, rounds=int, + w_dklen=WrappedDefault(None)) + def pbkdf2_hmac(space, name, password, salt, rounds, w_dklen): + digest = ropenssl.EVP_get_digestbyname(name) + if not digest: + raise oefmt(space.w_ValueError, "unknown hash function") + if space.is_w(w_dklen, space.w_None): + dklen = ropenssl.EVP_MD_size(digest) + else: + dklen = space.int_w(w_dklen) + if dklen < 1: + raise oefmt(space.w_ValueError, + "key length must be greater than 0.") + with rffi.scoped_alloc_buffer(dklen) as buf: + r = ropenssl.PKCS5_PBKDF2_HMAC( + password, len(password), salt, len(salt), rounds, digest, + dklen, buf.raw) + if not r: + raise ValueError + return space.wrap(buf.str(dklen)) diff --git a/pypy/module/_hashlib/test/test_hashlib.py b/pypy/module/_hashlib/test/test_hashlib.py --- a/pypy/module/_hashlib/test/test_hashlib.py +++ b/pypy/module/_hashlib/test/test_hashlib.py @@ -15,17 +15,19 @@ def test_attributes(self): import hashlib - for name, expected_size in {'md5': 16, - 'sha1': 20, - 'sha224': 28, - 'sha256': 32, - 'sha384': 48, - 'sha512': 64, - }.items(): + for name, (expected_size, expected_block_size) in { + 'md5': (16, 64), + 'sha1': (20, 64), + 'sha224': (28, 64), + 'sha256': (32, 64), + 'sha384': (48, 128), + 'sha512': (64, 128), + }.items(): h = hashlib.new(name) assert h.name == name assert h.digest_size == expected_size assert h.digestsize == expected_size + assert h.block_size == expected_block_size # h.update('abc') h2 = h.copy() @@ -46,6 +48,7 @@ h = py_new(name)('') assert h.digest_size == expected_size assert h.digestsize == expected_size + assert h.block_size == expected_block_size # h.update('abc') h2 = h.copy() @@ -108,3 +111,13 @@ got.decode('hex') if expected is not None: assert got == expected + + def test_pbkdf2(self): + try: + from _hashlib import pbkdf2_hmac + except ImportError: + skip("Requires OpenSSL >= 1.1") + out = pbkdf2_hmac('sha1', 'password', 'salt', 1) + assert out == '0c60c80f961f0e71f3a9b524af6012062fe037a6'.decode('hex') + out = pbkdf2_hmac('sha1', 'password', 'salt', 2, None) + assert out == 'ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957'.decode('hex') diff --git a/pypy/module/_socket/interp_socket.py b/pypy/module/_socket/interp_socket.py --- a/pypy/module/_socket/interp_socket.py +++ b/pypy/module/_socket/interp_socket.py @@ -479,6 +479,14 @@ @unwrap_spec(nbytes=int, flags=int) def recv_into_w(self, space, w_buffer, nbytes=0, flags=0): + """recv_into(buffer, [nbytes[, flags]]) -> nbytes_read + + A version of recv() that stores its data into a buffer rather than creating + a new string. Receive up to buffersize bytes from the socket. If buffersize + is not specified (or 0), receive up to the size available in the given buffer. + + See recv() for documentation about the flags. + """ rwbuffer = space.getarg_w('w*', w_buffer) lgt = rwbuffer.getlength() if nbytes == 0 or nbytes > lgt: @@ -490,6 +498,10 @@ @unwrap_spec(nbytes=int, flags=int) def recvfrom_into_w(self, space, w_buffer, nbytes=0, flags=0): + """recvfrom_into(buffer[, nbytes[, flags]]) -> (nbytes, address info) + + Like recv_into(buffer[, nbytes[, flags]]) but also return the sender's address info. + """ rwbuffer = space.getarg_w('w*', w_buffer) lgt = rwbuffer.getlength() if nbytes == 0: diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py --- a/pypy/module/_ssl/interp_ssl.py +++ b/pypy/module/_ssl/interp_ssl.py @@ -33,9 +33,10 @@ PY_SSL_CLIENT, PY_SSL_SERVER = 0, 1 (PY_SSL_VERSION_SSL2, PY_SSL_VERSION_SSL3, - PY_SSL_VERSION_SSL23, PY_SSL_VERSION_TLS1, PY_SSL_VERSION_TLS1_1, + PY_SSL_VERSION_TLS, PY_SSL_VERSION_TLS1, PY_SSL_VERSION_TLS1_1, PY_SSL_VERSION_TLS1_2) = range(6) + SOCKET_IS_NONBLOCKING, SOCKET_IS_BLOCKING = 0, 1 SOCKET_HAS_TIMED_OUT, SOCKET_HAS_BEEN_CLOSED = 2, 3 SOCKET_TOO_LARGE_FOR_SELECT, SOCKET_OPERATION_OK = 4, 5 @@ -68,11 +69,12 @@ constants["HAS_NPN"] = HAS_NPN constants["HAS_ALPN"] = HAS_ALPN +constants["PROTOCOL_TLS"] = PY_SSL_VERSION_TLS +constants["PROTOCOL_SSLv23"] = PY_SSL_VERSION_TLS # Legacy name if not OPENSSL_NO_SSL2: constants["PROTOCOL_SSLv2"] = PY_SSL_VERSION_SSL2 if not OPENSSL_NO_SSL3: constants["PROTOCOL_SSLv3"] = PY_SSL_VERSION_SSL3 -constants["PROTOCOL_SSLv23"] = PY_SSL_VERSION_SSL23 constants["PROTOCOL_TLSv1"] = PY_SSL_VERSION_TLS1 if HAVE_TLSv1_2: constants["PROTOCOL_TLSv1_1"] = PY_SSL_VERSION_TLS1_1 @@ -111,7 +113,10 @@ err_reason = libssl_ERR_GET_REASON(errcode) reason_str = ERROR_CODES_TO_NAMES.get((err_lib, err_reason), None) lib_str = LIBRARY_CODES_TO_NAMES.get(err_lib, None) - msg = rffi.charp2str(libssl_ERR_reason_error_string(errcode)) + raw_msg = libssl_ERR_reason_error_string(errcode) + msg = None + if raw_msg: + msg = rffi.charp2str(raw_msg) if not msg: msg = "unknown error" if reason_str and lib_str: @@ -637,9 +642,12 @@ if not self.ssl: return space.w_None comp_method = libssl_SSL_get_current_compression(self.ssl) - if not comp_method or intmask(comp_method[0].c_type) == NID_undef: + if not comp_method: return space.w_None - short_name = libssl_OBJ_nid2sn(comp_method[0].c_type) + method_type = intmask(libssl_COMP_get_type(comp_method)) + if method_type == NID_undef: + return space.w_None + short_name = libssl_COMP_get_name(comp_method) if not short_name: return space.w_None return space.wrap(rffi.charp2str(short_name)) @@ -795,7 +803,7 @@ for index in range(entry_count): entry = libssl_X509_NAME_get_entry(xname, index) # check to see if we've gotten to a new RDN - entry_level = intmask(entry[0].c_set) + entry_level = intmask(libssl_X509_NAME_ENTRY_set(entry)) if rdn_level >= 0: if rdn_level != entry_level: # yes, new RDN @@ -846,8 +854,9 @@ "No method for internalizing subjectAltName!'") with lltype.scoped_alloc(rffi.CCHARPP.TO, 1) as p_ptr: - p_ptr[0] = ext[0].c_value.c_data - length = intmask(ext[0].c_value.c_length) + ext_value = libssl_X509_EXTENSION_get_data(ext) + p_ptr[0] = ext_value.c_data + length = intmask(ext_value.c_length) null = lltype.nullptr(rffi.VOIDP.TO) if method[0].c_it: names = rffi.cast(GENERAL_NAMES, libssl_ASN1_item_d2i( @@ -967,10 +976,8 @@ if OPENSSL_VERSION_NUMBER >= 0x10001000: # Calls x509v3_cache_extensions and sets up crldp libssl_X509_check_ca(certificate) - dps = certificate[0].c_crldp - else: - dps = rffi.cast(stack_st_DIST_POINT, libssl_X509_get_ext_d2i( - certificate, NID_crl_distribution_points, None, None)) + dps = rffi.cast(stack_st_DIST_POINT, libssl_X509_get_ext_d2i( + certificate, NID_crl_distribution_points, None, None)) if not dps: return None @@ -1268,14 +1275,14 @@ @staticmethod @unwrap_spec(protocol=int) def descr_new(space, w_subtype, protocol): - if protocol == PY_SSL_VERSION_TLS1: + if protocol == PY_SSL_VERSION_TLS: + method = libssl_TLS_method() + elif protocol == PY_SSL_VERSION_TLS1: method = libssl_TLSv1_method() elif protocol == PY_SSL_VERSION_SSL3 and not OPENSSL_NO_SSL3: method = libssl_SSLv3_method() elif protocol == PY_SSL_VERSION_SSL2 and not OPENSSL_NO_SSL2: method = libssl_SSLv2_method() - elif protocol == PY_SSL_VERSION_SSL23: - method = libssl_SSLv23_method() elif protocol == PY_SSL_VERSION_TLS1_1 and HAVE_TLSv1_2: method = libssl_TLSv1_1_method() elif protocol == PY_SSL_VERSION_TLS1_2 and HAVE_TLSv1_2: @@ -1303,6 +1310,7 @@ # OpenSSL 1.0.2+), or use prime256v1 by default. # This is Apache mod_ssl's initialization # policy, so we should be safe. + # OpenSSL 1.1 has it enabled by default. if libssl_SSL_CTX_set_ecdh_auto: libssl_SSL_CTX_set_ecdh_auto(self.ctx, 1) else: @@ -1390,20 +1398,22 @@ def descr_get_verify_flags(self, space): store = libssl_SSL_CTX_get_cert_store(self.ctx) - flags = libssl_X509_VERIFY_PARAM_get_flags(store[0].c_param) + param = libssl_X509_STORE_get0_param(store) + flags = libssl_X509_VERIFY_PARAM_get_flags(param) return space.wrap(flags) def descr_set_verify_flags(self, space, w_obj): new_flags = space.int_w(w_obj) store = libssl_SSL_CTX_get_cert_store(self.ctx) - flags = libssl_X509_VERIFY_PARAM_get_flags(store[0].c_param) + param = libssl_X509_STORE_get0_param(store) + flags = libssl_X509_VERIFY_PARAM_get_flags(param) flags_clear = flags & ~new_flags flags_set = ~flags & new_flags if flags_clear and not libssl_X509_VERIFY_PARAM_clear_flags( - store[0].c_param, flags_clear): + param, flags_clear): raise _ssl_seterror(space, None, 0) if flags_set and not libssl_X509_VERIFY_PARAM_set_flags( - store[0].c_param, flags_set): + param, flags_set): raise _ssl_seterror(space, None, 0) def descr_get_check_hostname(self, space): @@ -1614,14 +1624,16 @@ x509 = 0 x509_ca = 0 crl = 0 - for i in range(libssl_sk_X509_OBJECT_num(store[0].c_objs)): - obj = libssl_sk_X509_OBJECT_value(store[0].c_objs, i) - if intmask(obj.c_type) == X509_LU_X509: + objs = libssl_X509_STORE_get0_objects(store) + for i in range(libssl_sk_X509_OBJECT_num(objs)): + obj = libssl_sk_X509_OBJECT_value(objs, i) + obj_type = intmask(libssl_X509_OBJECT_get_type(obj)) + if obj_type == X509_LU_X509: x509 += 1 if libssl_X509_check_ca( - libssl_pypy_X509_OBJECT_data_x509(obj)): + libssl_X509_OBJECT_get0_X509(obj)): x509_ca += 1 - elif intmask(obj.c_type) == X509_LU_CRL: + elif obj_type == X509_LU_CRL: crl += 1 else: # Ignore X509_LU_FAIL, X509_LU_RETRY, X509_LU_PKEY. @@ -1660,13 +1672,14 @@ binary_mode = False rlist = [] store = libssl_SSL_CTX_get_cert_store(self.ctx) - for i in range(libssl_sk_X509_OBJECT_num(store[0].c_objs)): - obj = libssl_sk_X509_OBJECT_value(store[0].c_objs, i) - if intmask(obj.c_type) != X509_LU_X509: + objs = libssl_X509_STORE_get0_objects(store) + for i in range(libssl_sk_X509_OBJECT_num(objs)): + obj = libssl_sk_X509_OBJECT_value(objs, i) + if intmask(libssl_X509_OBJECT_get_type(obj)) != X509_LU_X509: # not a x509 cert continue # CA for any purpose - cert = libssl_pypy_X509_OBJECT_data_x509(obj) + cert = libssl_X509_OBJECT_get0_X509(obj) if not libssl_X509_check_ca(cert): continue if binary_mode: diff --git a/pypy/module/_ssl/test/test_ssl.py b/pypy/module/_ssl/test/test_ssl.py --- a/pypy/module/_ssl/test/test_ssl.py +++ b/pypy/module/_ssl/test/test_ssl.py @@ -77,7 +77,7 @@ if sys.version_info < (2, 7, 9): ss = _ssl.sslwrap(s, 0) else: - ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLSv1) + ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLS) ss = ctx._wrap_socket(s, 0) assert ss.context is ctx exc = raises(_socket.error, ss.do_handshake) @@ -95,7 +95,7 @@ if sys.version_info < (2, 7, 9): ss = _ssl.sslwrap(s, 0) else: - ss = _ssl._SSLContext(_ssl.PROTOCOL_TLSv1)._wrap_socket(s, 0) + ss = _ssl._SSLContext(_ssl.PROTOCOL_TLS)._wrap_socket(s, 0) s.close() exc = raises(_ssl.SSLError, ss.write, "data") assert exc.value.message == 'Underlying socket has been closed.' @@ -123,13 +123,13 @@ def test_context(self): import _ssl - s = _ssl._SSLContext(_ssl.PROTOCOL_TLSv1) + s = _ssl._SSLContext(_ssl.PROTOCOL_TLS) raises(ValueError, _ssl._SSLContext, -1) assert type(s.options) is long - assert s.options & _ssl.OP_NO_SSLv2 - s.options &= ~_ssl.OP_NO_SSLv2 - assert not s.options & _ssl.OP_NO_SSLv2 + assert s.options & _ssl.OP_NO_SSLv3 + s.options &= ~_ssl.OP_NO_SSLv3 + assert not s.options & _ssl.OP_NO_SSLv3 raises(TypeError, "s.options = 2.5") assert not s.check_hostname @@ -159,7 +159,7 @@ def test_set_default_verify_paths(self): import _ssl - s = _ssl._SSLContext(_ssl.PROTOCOL_TLSv1) + s = _ssl._SSLContext(_ssl.PROTOCOL_TLS) s.set_default_verify_paths() @@ -253,13 +253,44 @@ if not _ssl.HAS_NPN: skip("NPN requires OpenSSL 1.0.1 or greater") - ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLSv1) + ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLS) ctx._set_npn_protocols(b'\x08http/1.1\x06spdy/2') ss = ctx._wrap_socket(self.s._sock, True, server_hostname="svn.python.org") self.s.close() del ss; gc.collect() + def test_peer_certificate(self): + import _ssl, gc + ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLS) + ss = ctx._wrap_socket(self.s._sock, False) + ss.do_handshake() + assert isinstance(ss.peer_certificate(der=True), bytes) + assert isinstance(ss.peer_certificate(), dict) + self.s.close() + del ss; gc.collect() + + def test_peer_certificate_verify(self): + import _ssl, ssl, gc + paths = ssl.get_default_verify_paths() + if not paths.capath and not paths.cafile: + skip("ssl.get_default_verify_paths() failed to return any path") + + ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLS) + ctx.verify_mode = _ssl.CERT_REQUIRED + ctx.load_verify_locations(capath=paths.capath, cafile=paths.cafile) + + ss = ctx._wrap_socket(self.s._sock, False) + try: + ss.do_handshake() + except _ssl.SSLError as e: + if e.reason == 'CERTIFICATE_VERIFY_FAILED': + skip("Certificate verification failed. " + "Most likely we just don't have any CA certificates.") + assert ss.peer_certificate() + self.s.close() + del ss; gc.collect() + def test_tls_unique_cb(self): import ssl, sys, gc ss = ssl.wrap_socket(self.s) @@ -325,7 +356,7 @@ def test_load_cert_chain(self): import _ssl, errno - ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLSv1) + ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLS) ctx.load_cert_chain(self.keycert) ctx.load_cert_chain(self.cert, self.key) exc = raises(IOError, ctx.load_cert_chain, "inexistent.pem") @@ -344,11 +375,11 @@ def test_load_verify_locations(self): import _ssl - ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLSv1) + ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLS) ctx.load_verify_locations(self.keycert) ctx.load_verify_locations(cafile=self.keycert, capath=None) - ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLSv1) + ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLS) with open(self.keycert) as f: cacert_pem = f.read().decode('ascii') ctx.load_verify_locations(cadata=cacert_pem) @@ -356,7 +387,7 @@ def test_get_ca_certs(self): import _ssl - ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLSv1) + ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLS) ctx.load_verify_locations(self.keycert) assert ctx.get_ca_certs() == [] ctx.load_verify_locations(self.python_org_cert) @@ -370,7 +401,7 @@ def test_cert_store_stats(self): import _ssl - ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLSv1) + ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLS) assert ctx.cert_store_stats() == {'x509_ca': 0, 'crl': 0, 'x509': 0} ctx.load_cert_chain(self.keycert) assert ctx.cert_store_stats() == {'x509_ca': 0, 'crl': 0, 'x509': 0} @@ -379,7 +410,7 @@ def test_load_dh_params(self): import _ssl, errno - ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLSv1) + ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLS) ctx.load_dh_params(self.dh512) raises(TypeError, ctx.load_dh_params) raises(TypeError, ctx.load_dh_params, None) @@ -389,7 +420,7 @@ def test_set_ecdh_curve(self): import _ssl - ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLSv1) + ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLS) ctx.set_ecdh_curve("prime256v1") raises(ValueError, ctx.set_ecdh_curve, "foo") @@ -434,7 +465,7 @@ def test_lib_reason(self): # Test the library and reason attributes import _ssl - ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLSv1) + ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLS) exc = raises(_ssl.SSLError, ctx.load_dh_params, self.keycert) assert exc.value.library == 'PEM' assert exc.value.reason == 'NO_START_LINE' @@ -445,7 +476,7 @@ # Check that the appropriate SSLError subclass is raised # (this only tests one of them) import _ssl, _socket - ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLSv1) + ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLS) s = _socket.socket() try: s.bind(("127.0.0.1", 0)) diff --git a/pypy/module/array/test/test_array.py b/pypy/module/array/test/test_array.py --- a/pypy/module/array/test/test_array.py +++ b/pypy/module/array/test/test_array.py @@ -2,7 +2,18 @@ import pytest -class BaseArrayTests: +class AppTestArray(object): + spaceconfig = {'usemodules': ['array', 'struct', '_rawffi', 'binascii']} + + def setup_class(cls): + cls.w_array = cls.space.appexec([], """(): + import array + return array.array + """) + cls.w_tempfile = cls.space.wrap( + str(pytest.ensuretemp('array').join('tmpfile'))) + cls.w_maxint = cls.space.wrap(sys.maxint) + def test_ctor(self): assert len(self.array('c')) == 0 assert len(self.array('i')) == 0 @@ -22,8 +33,8 @@ a = self.array('u') raises(TypeError, a.append, 7) raises(TypeError, a.append, u'hi') - a.append(unicode('h')) - assert a[0] == unicode('h') + a.append(u'h') + assert a[0] == u'h' assert type(a[0]) is unicode assert len(a) == 1 @@ -67,7 +78,7 @@ ('H', ( 0, 56783, 65535), int), ('i', (-32768, 30535, 32767), int), ('I', ( 0, 56783, 65535), long), - ('l', (-2 ** 32 / 2, 34, 2 ** 32 / 2 - 1), int), + ('l', (-2 ** 32 // 2, 34, 2 ** 32 // 2 - 1), int), ('L', (0, 3523532, 2 ** 32 - 1), long), ): a = self.array(tc, ok) @@ -105,7 +116,7 @@ assert a.tolist() == vals a = self.array(tc.lower()) - vals = [-1 * (2 ** itembits) / 2, (2 ** itembits) / 2 - 1] + vals = [-1 * (2 ** itembits) // 2, (2 ** itembits) // 2 - 1] a.fromlist(vals) assert a.tolist() == vals @@ -137,11 +148,11 @@ for t in inttypes: a = self.array(t, [1, 2, 3]) b = a.itemsize - for v in (-2 ** (8 * b) / 2, 2 ** (8 * b) / 2 - 1): + for v in (-2 ** (8 * b) // 2, 2 ** (8 * b) // 2 - 1): a[1] = v assert a[0] == 1 and a[1] == v and a[2] == 3 - raises(OverflowError, a.append, -2 ** (8 * b) / 2 - 1) - raises(OverflowError, a.append, 2 ** (8 * b) / 2) + raises(OverflowError, a.append, -2 ** (8 * b) // 2 - 1) + raises(OverflowError, a.append, 2 ** (8 * b) // 2) a = self.array(t.upper(), [1, 2, 3]) b = a.itemsize @@ -175,42 +186,35 @@ raises(ValueError, a.fromstring, '\x00' * (a.itemsize + 1)) raises(ValueError, a.fromstring, '\x00' * (2 * a.itemsize - 1)) raises(ValueError, a.fromstring, '\x00' * (2 * a.itemsize + 1)) - b = self.array(t, '\x00' * a.itemsize * 2) + b = self.array(t, b'\x00' * a.itemsize * 2) assert len(b) == 2 and b[0] == 0 and b[1] == 0 if sys.version_info >= (2, 7, 11): raises(ValueError, a.fromstring, a) def test_fromfile(self): - - ## class myfile(object): - ## def __init__(self, c, s): - ## self.c = c - ## self.s = s - ## def read(self,n): - ## return self.c*min(n,self.s) def myfile(c, s): - f = open(self.tempfile, 'w') + f = open(self.tempfile, 'wb') f.write(c * s) f.close() - return open(self.tempfile, 'r') + return open(self.tempfile, 'rb') - f = myfile('\x00', 100) + f = myfile(b'\x00', 100) for t in 'bBhHiIlLfd': a = self.array(t) a.fromfile(f, 2) assert len(a) == 2 and a[0] == 0 and a[1] == 0 a = self.array('b') - a.fromfile(myfile('\x01', 20), 2) + a.fromfile(myfile(b'\x01', 20), 2) assert len(a) == 2 and a[0] == 1 and a[1] == 1 a = self.array('h') - a.fromfile(myfile('\x01', 20), 2) + a.fromfile(myfile(b'\x01', 20), 2) assert len(a) == 2 and a[0] == 257 and a[1] == 257 for i in (0, 1): a = self.array('h') - raises(EOFError, a.fromfile, myfile('\x01', 2 + i), 2) + raises(EOFError, a.fromfile, myfile(b'\x01', 2 + i), 2) assert len(a) == 1 and a[0] == 257 def test_fromlist(self): @@ -250,12 +254,12 @@ assert repr(a) == "array('b', [1, 2, 1, 2])" def test_fromunicode(self): - raises(ValueError, self.array('i').fromunicode, unicode('hi')) + raises(ValueError, self.array('i').fromunicode, u'hi') a = self.array('u') - a.fromunicode(unicode('hi')) + a.fromunicode(u'hi') assert len(a) == 2 and a[0] == 'h' and a[1] == 'i' - b = self.array('u', unicode('hi')) + b = self.array('u', u'hi') assert len(b) == 2 and b[0] == 'h' and b[1] == 'i' def test_sequence(self): @@ -357,23 +361,6 @@ except ValueError: assert not ok - def test_reversingslice_pre26(self): - import sys - if sys.version_info >= (2, 6): - skip('arrays can handle more slice ops than lists in 2.6') - - for a in range(-4, 5): - for b in range(-4, 5): - for c in [-4, -3, -2, -1, 1, 2, 3, 4]: - lst = [1, 2, 3] - arr = self.array('i', lst) - for vals in ([4, 5], [6], []): - try: - lst[a:b:c] = vals - except ValueError: - raises(ValueError, - "arr[a:b:c]=self.array('i', vals)") - def test_toxxx(self): a = self.array('i', [1, 2, 3]) l = a.tolist() @@ -405,7 +392,7 @@ ('BHILfd', (127, 0, 1, 7, 255, 169)), ('hilHILfd', (32760, 30123, 3422, 23244))): for tc in tcodes: - values += ((2 ** self.array(tc).itemsize) / 2 - 1, ) + values += ((2 ** self.array(tc).itemsize) // 2 - 1, ) s = self.array(tc, values).tostring() a = unpack(tc * len(values), s) assert a == values @@ -420,8 +407,7 @@ assert repr(a) == "array('c', 'hi')" raises(ValueError, self.array('i').tounicode) - assert self.array('u', unicode('hello')).tounicode() == \ - unicode('hello') + assert self.array('u', u'hello').tounicode() == u'hello' def test_empty_tostring(self): a = self.array('l') @@ -493,14 +479,14 @@ def test_compare(self): class comparable(object): - def __cmp__(self, other): - return 0 + def __eq__(self, other): + return True class incomparable(object): pass for v1, v2, tt in (([1, 2, 3], [1, 3, 2], 'bhilBHIL'), ('abc', 'acb', 'c'), - (unicode('abc'), unicode('acb'), 'u')): + (u'abc', u'acb', 'u')): for t in tt: a = self.array(t, v1) b = self.array(t, v1) @@ -767,16 +753,16 @@ self.height = height return self - def _index(self, (x,y)): + def _index(self, x, y): x = min(max(x, 0), self.width-1) y = min(max(y, 0), self.height-1) return y * self.width + x def __getitem__(self, i): - return array.__getitem__(self, self._index(i)) + return array.__getitem__(self, self._index(*i)) def __setitem__(self, i, val): - return array.__setitem__(self, self._index(i), val) + return array.__setitem__(self, self._index(*i), val) img = Image(5, 10, 'B') for y in range(10): @@ -844,8 +830,8 @@ assert repr(mya('i', (1, 2, 3))) == "array('i', [1, 2, 3])" def test_unicode_outofrange(self): - a = self.array('u', unicode(r'\x01\u263a\x00\ufeff', 'unicode-escape')) - b = self.array('u', unicode(r'\x01\u263a\x00\ufeff', 'unicode-escape')) + a = self.array('u', u'\x01\u263a\x00\ufeff') + b = self.array('u', u'\x01\u263a\x00\ufeff') b.byteswap() assert a != b @@ -853,7 +839,7 @@ import sys if sys.maxunicode == 0xffff: skip("test for 32-bit unicodes") - a = self.array('u', '\xff\xff\xff\xff') + a = self.array('u', b'\xff\xff\xff\xff') assert len(a) == 1 assert repr(a[0]) == "u'\Uffffffff'" if sys.maxint == 2147483647: @@ -954,28 +940,6 @@ assert a[0] == u'b' -class TestCPythonsOwnArray(BaseArrayTests): - def setup_class(cls): - import array - cls.array = array.array - import struct - cls.struct = struct - cls.tempfile = str(pytest.ensuretemp('array').join('tmpfile')) - cls.maxint = sys.maxint - - -class AppTestArray(BaseArrayTests): - spaceconfig = {'usemodules': ['array', 'struct', '_rawffi', 'binascii']} - - def setup_class(cls): - cls.w_array = cls.space.appexec([], """(): - import array - return array.array - """) - cls.w_tempfile = cls.space.wrap( - str(pytest.ensuretemp('array').join('tmpfile'))) - cls.w_maxint = cls.space.wrap(sys.maxint) - def test_buffer_info(self): a = self.array('c', 'Hi!') bi = a.buffer_info() diff --git a/pypy/module/array/test/test_array_old.py b/pypy/module/array/test/test_array_old.py deleted file mode 100644 --- a/pypy/module/array/test/test_array_old.py +++ /dev/null @@ -1,114 +0,0 @@ -# minimal tests. See also lib-python/modified-2.4.1/test/test_array. - -import py -from py.test import raises -import struct - - -class BaseArrayTests: - # XXX very incomplete - - native_sizes = {'l': struct.calcsize('l')} - - def test_attributes(self): - a = self.array.array('c') - assert a.typecode == 'c' - assert a.itemsize == 1 - a = self.array.array('l') - assert a.typecode == 'l' - assert a.itemsize == self.native_sizes['l'] - - def test_imul(self): - a = self.array.array('i', [12, 34]) - a *= 3 - assert a.tolist() == [12, 34] * 3 - - def test_unicode(self): - a = self.array.array('u') - a.fromunicode(unichr(9999)) - assert len(a) == 1 - assert a.tolist() == [unichr(9999)] - - def test_pickle(self): - import sys - if sys.version_info < (2, 5): - py.test.skip("array.array not picklable before python 2.5") - import pickle - - for content in [[56, -12, 34], []]: - a = self.array.array('i', content) - a2 = pickle.loads(pickle.dumps(a)) - assert type(a2) is self.array.array - assert list(a2) == content - - def test_init_vs_new(self): - import sys - if sys.version_info < (2, 5): - py.test.skip("array.array constructor changed in 2.5") - class A(self.array.array): - def __init__(self, *args, **kwds): - self.args = args - self.kwds = kwds - - a = A('c', foo='bar') - assert a.args == ('c',) - assert a.kwds == {'foo': 'bar'} - a = A('i', range(10), some=42) - assert a.args == ('i', range(10)) - assert a.kwds == {'some': 42} - raises(TypeError, A) - raises(TypeError, A, 42) - raises(TypeError, A, 'i', [], []) - raises(TypeError, self.array.array, 'i', [], foo='bar') - - -class TestCPythonsOwnArray(BaseArrayTests): - - def setup_class(cls): - import array - cls.array = array - - -## class TestArrayOnTopOfCPython(BaseArrayTests): - -## def setup_class(cls): -## from pypy.tool.lib_pypy import LIB_PYPY -## if not hasattr(struct, 'pack_into'): -## py.test.skip("requires CPython >= 2.5") -## import new -## path = LIB_PYPY.join('array.py') -## myarraymodule = new.module('array') -## execfile(str(path), myarraymodule.__dict__) -## cls.array = myarraymodule - -## def test_unicode(self): -## py.test.skip("no 'u' type code in CPython's struct module") - -## def test_pickle(self): -## py.test.skip("pickle getting confused by the hack in setup_class()") - - -class AppTestArray(BaseArrayTests): - spaceconfig = {'usemodules': ['struct', 'array', 'binascii']} - - def setup_class(cls): - """Import the array module and make it available as self.array.""" - cls.w_array = cls.space.getbuiltinmodule('array') - cls.w_native_sizes = cls.space.wrap(cls.native_sizes) - - -## class AppTestArrayWithRawFFI(AppTestArray): -## """ -## The same as the base class, but with a space that also includes the -## _rawffi module. The array module internally uses it in this case. -## """ -## spaceconfig = dict(usemodules=['struct', '_rawffi']) - -## def test_buffer_info(self): -## a = self.array.array('l', [123, 456]) -## assert a.itemsize == self.native_sizes['l'] -## address, length = a.buffer_info() -## assert length == 2 # and not 2 * self.native_sizes['l'] -## assert address != 0 -## # should check the address via some unsafe peeking, but it's -## # not easy on top of py.py diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py --- a/pypy/module/cpyext/api.py +++ b/pypy/module/cpyext/api.py @@ -79,11 +79,16 @@ CONST_STRING = lltype.Ptr(lltype.Array(lltype.Char, hints={'nolength': True}), use_cache=False) +CONST_STRINGP = lltype.Ptr(lltype.Array(rffi.CCHARP, + hints={'nolength': True}), + use_cache=False) CONST_WSTRING = lltype.Ptr(lltype.Array(lltype.UniChar, hints={'nolength': True}), use_cache=False) assert CONST_STRING is not rffi.CCHARP assert CONST_STRING == rffi.CCHARP +assert CONST_STRINGP is not rffi.CCHARPP +assert CONST_STRINGP == rffi.CCHARPP assert CONST_WSTRING is not rffi.CWCHARP assert CONST_WSTRING == rffi.CWCHARP @@ -1004,6 +1009,8 @@ for i, argtype in enumerate(func.argtypes): if argtype is CONST_STRING: arg = 'const char *@' + elif argtype is CONST_STRINGP: + arg = 'const char **@' elif argtype is CONST_WSTRING: arg = 'const wchar_t *@' else: diff --git a/pypy/module/cpyext/buffer.py b/pypy/module/cpyext/buffer.py --- a/pypy/module/cpyext/buffer.py +++ b/pypy/module/cpyext/buffer.py @@ -2,7 +2,6 @@ from pypy.module.cpyext.api import ( cpython_api, CANNOT_FAIL, Py_TPFLAGS_HAVE_NEWBUFFER) from pypy.module.cpyext.pyobject import PyObject -from pypy.module.cpyext.bytesobject import PyBytesObject @cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL) def PyObject_CheckBuffer(space, pyobj): diff --git a/pypy/module/cpyext/memoryobject.py b/pypy/module/cpyext/memoryobject.py --- a/pypy/module/cpyext/memoryobject.py +++ b/pypy/module/cpyext/memoryobject.py @@ -1,6 +1,6 @@ from pypy.module.cpyext.api import (cpython_api, Py_buffer, CANNOT_FAIL, Py_MAX_FMT, Py_MAX_NDIMS, build_type_checkers, Py_ssize_tP) -from pypy.module.cpyext.pyobject import PyObject, make_ref, incref +from pypy.module.cpyext.pyobject import PyObject, make_ref, incref, from_ref from rpython.rtyper.lltypesystem import lltype, rffi from rpython.rlib.rarithmetic import widen from pypy.objspace.std.memoryobject import W_MemoryView @@ -132,11 +132,22 @@ def PyMemoryView_FromObject(space, w_obj): return space.call_method(space.builtin, "memoryview", w_obj) +@cpython_api([lltype.Ptr(Py_buffer)], PyObject) +def PyMemoryView_FromBuffer(space, view): + """Create a memoryview object wrapping the given buffer-info structure view. + The memoryview object then owns the buffer, which means you shouldn't + try to release it yourself: it will be released on deallocation of the + memoryview object.""" + w_obj = from_ref(space, view.c_obj) + if isinstance(w_obj, W_MemoryView): + return w_obj + return space.call_method(space.builtin, "memoryview", w_obj) + @cpython_api([PyObject], PyObject) def PyMemoryView_GET_BASE(space, w_obj): # return the obj field of the Py_buffer created by PyMemoryView_GET_BUFFER # XXX needed for numpy on py3k - raise NotImplementedError('PyMemoryView_GET_BUFFER') + raise NotImplementedError('PyMemoryView_GET_BASE') @cpython_api([PyObject], lltype.Ptr(Py_buffer), error=CANNOT_FAIL) def PyMemoryView_GET_BUFFER(space, w_obj): diff --git a/pypy/module/cpyext/methodobject.py b/pypy/module/cpyext/methodobject.py --- a/pypy/module/cpyext/methodobject.py +++ b/pypy/module/cpyext/methodobject.py @@ -311,7 +311,7 @@ def PyClassMethod_New(space, w_func): return space.wrap(ClassMethod(w_func)) -@cpython_api([PyObject, lltype.Ptr(PyMethodDef)], PyObject) +@cpython_api([PyTypeObjectPtr, lltype.Ptr(PyMethodDef)], PyObject) def PyDescr_NewMethod(space, w_type, method): return space.wrap(W_PyCMethodObject(space, method, w_type)) diff --git a/pypy/module/cpyext/object.py b/pypy/module/cpyext/object.py --- a/pypy/module/cpyext/object.py +++ b/pypy/module/cpyext/object.py @@ -3,7 +3,7 @@ cpython_api, generic_cpy_call, CANNOT_FAIL, Py_ssize_t, Py_ssize_tP, PyVarObject, Py_buffer, size_t, Py_TPFLAGS_HEAPTYPE, Py_LT, Py_LE, Py_EQ, Py_NE, Py_GT, - Py_GE, CONST_STRING, FILEP, fwrite) + Py_GE, CONST_STRING, CONST_STRINGP, FILEP, fwrite) from pypy.module.cpyext.pyobject import ( PyObject, PyObjectP, create_ref, from_ref, Py_IncRef, Py_DecRef, get_typedescr, _Py_NewReference) @@ -429,7 +429,7 @@ is active then NULL is returned but PyErr_Occurred() will return false.""" return space.call_function(space.builtin.get('dir'), w_o) -@cpython_api([PyObject, rffi.CCHARPP, Py_ssize_tP], rffi.INT_real, error=-1) +@cpython_api([PyObject, CONST_STRINGP, Py_ssize_tP], rffi.INT_real, error=-1) def PyObject_AsCharBuffer(space, obj, bufferp, sizep): """Returns a pointer to a read-only memory location usable as character-based input. The obj argument must support the single-segment diff --git a/pypy/module/cpyext/pyerrors.py b/pypy/module/cpyext/pyerrors.py --- a/pypy/module/cpyext/pyerrors.py _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit