[pypy-commit] pypy py3.5: merge heads
arigo
pypy.commits at gmail.com
Wed Dec 7 10:44:43 EST 2016
Author: Armin Rigo <arigo at tunes.org>
Branch: py3.5
Changeset: r88953:3ee658af45ba
Date: 2016-12-07 16:43 +0100
http://bitbucket.org/pypy/pypy/changeset/3ee658af45ba/
Log: merge heads
diff --git a/lib-python/3/test/test_builtin.py b/lib-python/3/test/test_builtin.py
--- a/lib-python/3/test/test_builtin.py
+++ b/lib-python/3/test/test_builtin.py
@@ -16,7 +16,8 @@
import warnings
from operator import neg
from test.support import (
- TESTFN, unlink, run_unittest, check_warnings, check_impl_detail)
+ TESTFN, unlink, run_unittest, check_warnings, check_impl_detail,
+ cpython_only)
from test.support.script_helper import assert_python_ok
try:
import pty, signal
@@ -1640,6 +1641,8 @@
class ShutdownTest(unittest.TestCase):
+ # PyPy doesn't do a gc.collect() at shutdown
+ @cpython_only
def test_cleanup(self):
# Issue #19255: builtins are still available at shutdown
code = """if 1:
diff --git a/lib_pypy/_cffi_ssl/_cffi_src/openssl/crypto.py b/lib_pypy/_cffi_ssl/_cffi_src/openssl/crypto.py
--- a/lib_pypy/_cffi_ssl/_cffi_src/openssl/crypto.py
+++ b/lib_pypy/_cffi_ssl/_cffi_src/openssl/crypto.py
@@ -53,6 +53,7 @@
const char *OpenSSL_version(int);
/* this is a macro in 1.1.0 */
+void *OPENSSL_malloc(size_t);
void OPENSSL_free(void *);
/* This was removed in 1.1.0 */
diff --git a/lib_pypy/_cffi_ssl/_cffi_src/openssl/evp.py b/lib_pypy/_cffi_ssl/_cffi_src/openssl/evp.py
--- a/lib_pypy/_cffi_ssl/_cffi_src/openssl/evp.py
+++ b/lib_pypy/_cffi_ssl/_cffi_src/openssl/evp.py
@@ -25,6 +25,13 @@
static const int EVP_CTRL_GCM_GET_TAG;
static const int EVP_CTRL_GCM_SET_TAG;
+typedef struct {
+ int type;
+ int alias;
+ const char *name;
+ const char *data;
+} OBJ_NAME;
+
static const int Cryptography_HAS_GCM;
static const int Cryptography_HAS_PBKDF2_HMAC;
static const int Cryptography_HAS_PKEY_CTX;
@@ -136,6 +143,7 @@
without worrying about what OpenSSL we're running against. */
EVP_MD_CTX *Cryptography_EVP_MD_CTX_new(void);
void Cryptography_EVP_MD_CTX_free(EVP_MD_CTX *);
+void OBJ_NAME_do_all(int, void (*) (const OBJ_NAME *, void *), void *);
"""
MACROS = """
@@ -156,6 +164,7 @@
EC_KEY *EVP_PKEY_get1_EC_KEY(EVP_PKEY *);
int EVP_PKEY_set1_EC_KEY(EVP_PKEY *, EC_KEY *);
+int EVP_MD_CTX_block_size(const EVP_MD_CTX *md);
int EVP_CIPHER_CTX_block_size(const EVP_CIPHER_CTX *);
int EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *, int, int, void *);
@@ -167,6 +176,7 @@
int EVP_PBE_scrypt(const char *, size_t, const unsigned char *, size_t,
uint64_t, uint64_t, uint64_t, uint64_t, unsigned char *,
size_t);
+#define OBJ_NAME_TYPE_MD_METH ...
"""
CUSTOMIZATIONS = """
diff --git a/lib_pypy/_cffi_ssl/_cffi_src/openssl/ssl.py b/lib_pypy/_cffi_ssl/_cffi_src/openssl/ssl.py
--- a/lib_pypy/_cffi_ssl/_cffi_src/openssl/ssl.py
+++ b/lib_pypy/_cffi_ssl/_cffi_src/openssl/ssl.py
@@ -26,7 +26,6 @@
static const long Cryptography_HAS_SSL_CTX_SET_CLIENT_CERT_ENGINE;
static const long Cryptography_HAS_SSL_CTX_CLEAR_OPTIONS;
static const long Cryptography_HAS_NPN_NEGOTIATED;
-static const long Cryptography_OPENSSL_NO_TLSEXT;
/* Internally invented symbol to tell us if SNI is supported */
static const long Cryptography_HAS_TLSEXT_HOSTNAME;
@@ -138,6 +137,7 @@
typedef ... SSL_CTX;
typedef ... SSL_SESSION;
+
typedef ... SSL;
static const long TLSEXT_NAMETYPE_host_name;
@@ -434,7 +434,6 @@
long SSL_CTX_sess_misses(SSL_CTX *);
long SSL_CTX_sess_timeouts(SSL_CTX *);
long SSL_CTX_sess_cache_full(SSL_CTX *);
-
"""
CUSTOMIZATIONS = """
@@ -689,12 +688,6 @@
static const long Cryptography_HAS_SSL_CTX_CLEAR_OPTIONS = 1;
-#ifdef OPENSSL_NO_TLSEXT
-static const long Cryptography_OPENSSL_NO_TLSEXT = 1;
-#else
-static const long Cryptography_OPENSSL_NO_TLSEXT = 0;
-#endif
-
/* in OpenSSL 1.1.0 the SSL_ST values were renamed to TLS_ST and several were
removed */
#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 || defined(LIBRESSL_VERSION_NUMBER)
diff --git a/lib_pypy/_cffi_ssl/_cffi_src/openssl/x509_vfy.py b/lib_pypy/_cffi_ssl/_cffi_src/openssl/x509_vfy.py
--- a/lib_pypy/_cffi_ssl/_cffi_src/openssl/x509_vfy.py
+++ b/lib_pypy/_cffi_ssl/_cffi_src/openssl/x509_vfy.py
@@ -140,6 +140,7 @@
int X509_STORE_set_flags(X509_STORE *, unsigned long);
void X509_STORE_free(X509_STORE *);
+
/* X509_STORE_CTX */
X509_STORE_CTX *X509_STORE_CTX_new(void);
void X509_STORE_CTX_cleanup(X509_STORE_CTX *);
@@ -201,7 +202,7 @@
int sk_X509_OBJECT_num(Cryptography_STACK_OF_X509_OBJECT *);
X509_OBJECT *sk_X509_OBJECT_value(Cryptography_STACK_OF_X509_OBJECT *, int);
-X509_VERIFY_PARAM * X509_STORE_get0_param(X509_STORE *);
+X509_VERIFY_PARAM *X509_STORE_get0_param(X509_STORE *);
Cryptography_STACK_OF_X509_OBJECT *X509_STORE_get0_objects(X509_STORE *);
X509 *X509_OBJECT_get0_X509(X509_OBJECT *);
int X509_OBJECT_get_type(const X509_OBJECT *);
diff --git a/lib_pypy/_hashlib/__init__.py b/lib_pypy/_hashlib/__init__.py
new file mode 100644
--- /dev/null
+++ b/lib_pypy/_hashlib/__init__.py
@@ -0,0 +1,172 @@
+import sys
+from threading import Lock
+from _pypy_openssl import ffi, lib
+from _cffi_ssl._stdssl.utility import (_str_to_ffi_buffer, _bytes_with_len,
+ _str_from_buf)
+
+def new(name, string=b''):
+ h = Hash(name)
+ h.update(string)
+ return h
+
+class Hash(object):
+
+ def __init__(self, name, copy_from=None):
+ self.ctx = ffi.NULL
+ self.name = name
+ digest_type = self.digest_type_by_name()
+ self.digest_size = lib.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()
+
+ ctx = lib.Cryptography_EVP_MD_CTX_new()
+ if ctx == ffi.NULL:
+ raise MemoryError
+ ctx = ffi.gc(ctx, lib.Cryptography_EVP_MD_CTX_free)
+
+ try:
+ if copy_from is not None:
+ # cpython uses EVP_MD_CTX_copy(...)
+ if not lib.EVP_MD_CTX_copy_ex(ctx, copy_from):
+ raise ValueError
+ else:
+ # cpython uses EVP_DigestInit
+ lib.EVP_DigestInit_ex(ctx, digest_type, ffi.NULL)
+ self.ctx = ctx
+ except:
+ # no need to gc ctx!
+ raise
+
+ def digest_type_by_name(self):
+ c_name = _str_to_ffi_buffer(self.name)
+ digest_type = lib.EVP_get_digestbyname(c_name)
+ if not digest_type:
+ raise ValueError("unknown hash function")
+ # TODO
+ return digest_type
+
+ def __repr__(self):
+ return "<%s HASH object at 0x%s>" % (self.name, id(self))
+
+ def update(self, string):
+ buf = ffi.from_buffer(string)
+ with self.lock:
+ # XXX try to not release the GIL for small requests
+ lib.EVP_DigestUpdate(self.ctx, buf, len(buf))
+
+ def copy(self):
+ """Return a copy of the hash object."""
+ with self.lock:
+ return Hash(self.name, copy_from=self.ctx)
+
+ def digest(self):
+ """Return the digest value as a string of binary data."""
+ return self._digest()
+
+ def hexdigest(self):
+ """Return the digest value as a string of hexadecimal digits."""
+ digest = self._digest()
+ hexdigits = '0123456789abcdef'
+ result = []
+ for c in digest:
+ result.append(hexdigits[(c >> 4) & 0xf])
+ result.append(hexdigits[ c & 0xf])
+ return ''.join(result)
+
+ @property
+ def block_size(self):
+ return lib.EVP_MD_CTX_block_size(self.ctx)
+
+ def _digest(self):
+ ctx = lib.Cryptography_EVP_MD_CTX_new()
+ if ctx == ffi.NULL:
+ raise MemoryError
+ try:
+ with self.lock:
+ if not lib.EVP_MD_CTX_copy_ex(ctx, self.ctx):
+ raise ValueError
+ digest_size = self.digest_size
+ buf = ffi.new("unsigned char[]", digest_size)
+ lib.EVP_DigestFinal_ex(ctx, buf, ffi.NULL)
+ return _bytes_with_len(buf, digest_size)
+ finally:
+ lib.Cryptography_EVP_MD_CTX_free(ctx)
+
+algorithms = ('md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512')
+
+class NameFetcher:
+ def __init__(self):
+ self.meth_names = []
+ self.error = None
+
+
+def _fetch_names():
+ name_fetcher = NameFetcher()
+ handle = ffi.new_handle(name_fetcher)
+ lib.OBJ_NAME_do_all(lib.OBJ_NAME_TYPE_MD_METH, hash_name_mapper_callback, handle)
+ if name_fetcher.error:
+ raise name_fetcher.error
+ meth_names = name_fetcher.meth_names
+ name_fetcher.meth_names = None
+ return frozenset(meth_names)
+
+ at ffi.callback("void(OBJ_NAME*, void*)")
+def hash_name_mapper_callback(obj_name, userdata):
+ if not obj_name:
+ return
+ name_fetcher = ffi.from_handle(userdata)
+ # Ignore aliased names, they pollute the list and OpenSSL appears
+ # to have a its own definition of alias as the resulting list
+ # still contains duplicate and alternate names for several
+ # algorithms.
+ if obj_name.alias != 0:
+ return
+ name = _str_from_buf(obj_name.name)
+ name_fetcher.meth_names.append(name)
+
+openssl_md_meth_names = _fetch_names()
+del _fetch_names
+
+# shortcut functions
+def make_new_hash(name, funcname):
+ def new_hash(string=b''):
+ return new(name, string)
+ new_hash.__name__ = funcname
+ return new_hash
+
+for _name in algorithms:
+ _newname = 'openssl_%s' % (_name,)
+ globals()[_newname] = make_new_hash(_name, _newname)
+
+if hasattr(lib, 'PKCS5_PBKDF2_HMAC'):
+ #@unwrap_spec(name=str, password='bytes', salt='bytes', iterations=int,
+ # w_dklen=WrappedDefault(None))
+ def pbkdf2_hmac(name, password, salt, iterations, dklen=None):
+ if not isinstance(name, str):
+ raise TypeError("expected 'str' for name, but got %s" % type(name))
+ c_name = _str_to_ffi_buffer(name)
+ digest = lib.EVP_get_digestbyname(c_name)
+ if digest == ffi.NULL:
+ raise ValueError("unsupported hash type")
+ if dklen is None:
+ dklen = lib.EVP_MD_size(digest)
+ if dklen < 1:
+ raise ValueError("key length must be greater than 0.")
+ if dklen >= sys.maxsize:
+ raise OverflowError("key length is too great.")
+ if iterations < 1:
+ raise ValueError("iteration value must be greater than 0.")
+ if iterations >= sys.maxsize:
+ raise OverflowError("iteration value is too great.")
+ buf = ffi.new("unsigned char[]", dklen)
+ c_password = ffi.from_buffer(bytes(password))
+ c_salt = ffi.from_buffer(bytes(salt))
+ r = lib.PKCS5_PBKDF2_HMAC(c_password, len(c_password),
+ ffi.cast("unsigned char*",c_salt), len(c_salt),
+ iterations, digest, dklen, buf)
+ if r == 0:
+ raise ValueError
+ return _bytes_with_len(buf, dklen)
diff --git a/lib_pypy/_sqlite3.py b/lib_pypy/_sqlite3.py
--- a/lib_pypy/_sqlite3.py
+++ b/lib_pypy/_sqlite3.py
@@ -149,10 +149,11 @@
def connect(database, timeout=5.0, detect_types=0, isolation_level="",
- check_same_thread=True, factory=None, cached_statements=100):
+ check_same_thread=True, factory=None, cached_statements=100,
+ uri=0):
factory = Connection if not factory else factory
return factory(database, timeout, detect_types, isolation_level,
- check_same_thread, factory, cached_statements)
+ check_same_thread, factory, cached_statements, uri)
def _unicode_text_factory(x):
@@ -195,14 +196,23 @@
_db = None
def __init__(self, database, timeout=5.0, detect_types=0, isolation_level="",
- check_same_thread=True, factory=None, cached_statements=100):
+ check_same_thread=True, factory=None, cached_statements=100, uri=0):
self.__initialized = True
db_star = _ffi.new('sqlite3 **')
if isinstance(database, unicode):
database = database.encode('utf-8')
- if _lib.sqlite3_open(database, db_star) != _lib.SQLITE_OK:
- raise OperationalError("Could not open database")
+ if _lib.SQLITE_OPEN_URI != 0:
+ if uri and _lib.SQLITE_OPEN_URI == 0:
+ raise NotSupportedError("URIs not supported")
+ flags = _lib.SQLITE_OPEN_READWRITE | _lib.SQLITE_OPEN_CREATE
+ if uri:
+ flags |= _lib.SQLITE_OPEN_URI
+ if _lib.sqlite3_open_v2(database, db_star, flags, _ffi.NULL) != _lib.SQLITE_OK:
+ raise OperationalError("Could not open database")
+ else:
+ if _lib.sqlite3_open(database, db_star) != _lib.SQLITE_OK:
+ raise OperationalError("Could not open database")
self._db = db_star[0]
if timeout is not None:
timeout = int(timeout * 1000) # pysqlite2 uses timeout in seconds
@@ -1195,6 +1205,8 @@
def __getitem__(self, item):
if isinstance(item, (int, long)):
return self.values[item]
+ elif isinstance(item, slice):
+ return self.values[item]
else:
item = item.lower()
for idx, desc in enumerate(self.description):
diff --git a/lib_pypy/_sqlite3_build.py b/lib_pypy/_sqlite3_build.py
--- a/lib_pypy/_sqlite3_build.py
+++ b/lib_pypy/_sqlite3_build.py
@@ -103,6 +103,10 @@
#define SQLITE_DROP_VTABLE ...
#define SQLITE_FUNCTION ...
+static const long SQLITE_OPEN_URI;
+static const long SQLITE_OPEN_READWRITE;
+static const long SQLITE_OPEN_CREATE;
+
const char *sqlite3_libversion(void);
typedef ... sqlite3;
@@ -117,6 +121,13 @@
sqlite3 **ppDb /* OUT: SQLite db handle */
);
+int sqlite3_open_v2(
+ const char *filename, /* Database filename (UTF-8) */
+ sqlite3 **ppDb, /* OUT: SQLite db handle */
+ int flags, /* Flags */
+ const char *zVfs /* Name of VFS module to use */
+);
+
int sqlite3_close(sqlite3 *);
int sqlite3_busy_timeout(sqlite3*, int ms);
@@ -259,7 +270,21 @@
libraries=['sqlite3']
)
-_ffi.set_source("_sqlite3_cffi", "#include <sqlite3.h>", **extra_args)
+SOURCE = """
+#include <sqlite3.h>
+
+#ifndef SQLITE_OPEN_URI
+static const long SQLITE_OPEN_URI = 0;
+#endif
+#ifndef SQLITE_OPEN_READWRITE
+static const long SQLITE_OPEN_READWRITE = 0;
+#endif
+#ifndef SQLITE_OPEN_CREATE
+static const long SQLITE_OPEN_CREATE = 0;
+#endif
+"""
+
+_ffi.set_source("_sqlite3_cffi", SOURCE, **extra_args)
if __name__ == "__main__":
diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py
--- a/pypy/config/pypyoption.py
+++ b/pypy/config/pypyoption.py
@@ -35,7 +35,7 @@
working_modules.update([
"_socket", "unicodedata", "mmap", "fcntl", "_locale", "pwd",
"select", "zipimport", "_lsprof", "crypt", "signal", "_rawffi", "termios",
- "zlib", "bz2", "struct", "_hashlib", "_md5", "_minimal_curses",
+ "zlib", "bz2", "struct", "_md5", "_minimal_curses",
"thread", "itertools", "pyexpat", "cpyext", "array",
"binascii", "_multiprocessing", '_warnings', "_collections",
"_multibytecodec", "_continuation", "_cffi_backend",
@@ -118,7 +118,6 @@
"zlib" : ["rpython.rlib.rzlib"],
"bz2" : ["pypy.module.bz2.interp_bz2"],
"pyexpat" : ["pypy.module.pyexpat.interp_pyexpat"],
- "_hashlib" : ["pypy.module._ssl.interp_ssl"],
"_minimal_curses": ["pypy.module._minimal_curses.fficurses"],
"_continuation": ["rpython.rlib.rstacklet"],
"_vmprof" : ["pypy.module._vmprof.interp_vmprof"],
diff --git a/pypy/interpreter/test/test_appinterp.py b/pypy/interpreter/test/test_appinterp.py
--- a/pypy/interpreter/test/test_appinterp.py
+++ b/pypy/interpreter/test/test_appinterp.py
@@ -156,7 +156,7 @@
assert space1.str_w(w_str) == "hello"
class TestMixedModuleUnfreeze:
- spaceconfig = dict(usemodules=('_ssl', '_socket'))
+ spaceconfig = dict(usemodules=('_socket',))
def test_random_stuff_can_unfreeze(self):
# When a module contains an "import" statement in applevel code, the
@@ -167,13 +167,13 @@
# at runtime, like setting os.environ (posix module) or initializing
# the winsock library (_socket module)
w_socket = self.space.builtin_modules['_socket']
- w_ssl = self.space.builtin_modules['_ssl']
+ # _ssl is not builtin anymore, this test also tried to _cleanup_ on
+ # the wrapped ssl object
+ # w_ssl = self.space.builtin_modules['_ssl']
# Uncomment this line for a workaround
# space.getattr(w_ssl, space.wrap('SSLError'))
w_socket._cleanup_()
assert w_socket.startup_called == False
- w_ssl._cleanup_() # w_ssl.appleveldefs['SSLError'] imports _socket
- assert w_socket.startup_called == False
diff --git a/pypy/module/_hashlib/__init__.py b/pypy/module/_hashlib/__init__.py
deleted file mode 100644
--- a/pypy/module/_hashlib/__init__.py
+++ /dev/null
@@ -1,22 +0,0 @@
-from pypy.interpreter.mixedmodule import MixedModule
-from pypy.module._hashlib.interp_hashlib import (
- algorithms, fetch_names, HAS_FAST_PKCS5_PBKDF2_HMAC)
-
-
-class Module(MixedModule):
- interpleveldefs = {
- 'new' : 'interp_hashlib.new',
- }
-
- appleveldefs = {
- }
-
- 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
deleted file mode 100644
--- a/pypy/module/_hashlib/interp_hashlib.py
+++ /dev/null
@@ -1,209 +0,0 @@
-from __future__ import with_statement
-
-from rpython.rlib import rgc, ropenssl
-from rpython.rlib.objectmodel import we_are_translated
-from rpython.rlib.rstring import StringBuilder
-from rpython.rtyper.lltypesystem import lltype, rffi
-from rpython.tool.sourcetools import func_renamer
-
-from pypy.interpreter.baseobjspace import W_Root
-from pypy.interpreter.error import OperationError, oefmt
-from pypy.interpreter.gateway import unwrap_spec, interp2app, WrappedDefault
-from pypy.interpreter.typedef import TypeDef, GetSetProperty
-from pypy.module.thread.os_lock import Lock
-
-
-algorithms = ('md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512')
-
-def hash_name_mapper_callback(obj_name, userdata):
- if not obj_name:
- return
- # Ignore aliased names, they pollute the list and OpenSSL appears
- # to have a its own definition of alias as the resulting list
- # still contains duplicate and alternate names for several
- # algorithms.
- if rffi.cast(lltype.Signed, obj_name[0].c_alias):
- return
- try:
- space = global_name_fetcher.space
- w_name = space.wrap(rffi.charp2str(obj_name[0].c_name))
- global_name_fetcher.meth_names.append(w_name)
- except OperationError as e:
- global_name_fetcher.w_error = e
-
-class NameFetcher:
- def setup(self, space):
- self.space = space
- self.meth_names = []
- self.w_error = None
- def _cleanup_(self):
- self.__dict__.clear()
-global_name_fetcher = NameFetcher()
-
-def fetch_names(space):
- global_name_fetcher.setup(space)
- ropenssl.init_digests()
- ropenssl.OBJ_NAME_do_all(ropenssl.OBJ_NAME_TYPE_MD_METH,
- hash_name_mapper_callback, None)
- if global_name_fetcher.w_error:
- raise global_name_fetcher.w_error
- meth_names = global_name_fetcher.meth_names
- global_name_fetcher.meth_names = None
- return space.call_function(space.w_frozenset, space.newlist(meth_names))
-
-class W_Hash(W_Root):
- NULL_CTX = lltype.nullptr(ropenssl.EVP_MD_CTX.TO)
- ctx = NULL_CTX
-
- def __init__(self, space, name, copy_from=NULL_CTX):
- self.name = name
- digest_type = self.digest_type_by_name(space)
- 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 = 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:
- if not ropenssl.EVP_MD_CTX_copy(ctx, copy_from):
- raise ValueError
- else:
- ropenssl.EVP_DigestInit(ctx, digest_type)
- self.ctx = ctx
- except:
- ropenssl.EVP_MD_CTX_free(ctx)
- raise
- self.register_finalizer(space)
-
- def _finalize_(self):
- ctx = self.ctx
- if ctx:
- self.ctx = lltype.nullptr(ropenssl.EVP_MD_CTX.TO)
- ropenssl.EVP_MD_CTX_free(ctx)
-
- def digest_type_by_name(self, space):
- digest_type = ropenssl.EVP_get_digestbyname(self.name)
- if not digest_type:
- raise oefmt(space.w_ValueError, "unknown hash function")
- return digest_type
-
- def descr_repr(self, space):
- addrstring = self.getaddrstring(space)
- return space.wrap("<%s HASH object at 0x%s>" % (
- self.name, addrstring))
-
- @unwrap_spec(string='bufferstr')
- def update(self, space, string):
- with rffi.scoped_nonmovingbuffer(string) as buf:
- with self.lock:
- # XXX try to not release the GIL for small requests
- ropenssl.EVP_DigestUpdate(self.ctx, buf, len(string))
-
- def copy(self, space):
- "Return a copy of the hash object."
- with self.lock:
- return W_Hash(space, self.name, copy_from=self.ctx)
-
- def digest(self, space):
- "Return the digest value as a string of binary data."
- digest = self._digest(space)
- return space.newbytes(digest)
-
- def hexdigest(self, space):
- "Return the digest value as a string of hexadecimal digits."
- digest = self._digest(space)
- hexdigits = '0123456789abcdef'
- result = StringBuilder(self.digest_size * 2)
- for c in digest:
- result.append(hexdigits[(ord(c) >> 4) & 0xf])
- result.append(hexdigits[ ord(c) & 0xf])
- return space.wrap(result.build())
-
- def get_digest_size(self, space):
- return space.wrap(self.digest_size)
-
- def get_block_size(self, space):
- digest_type = self.digest_type_by_name(space)
- 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):
- ctx = ropenssl.EVP_MD_CTX_new()
- if ctx is None:
- raise MemoryError
- try:
- with self.lock:
- 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)
- return buf.str(digest_size)
- finally:
- ropenssl.EVP_MD_CTX_free(ctx)
-
-
-W_Hash.typedef = TypeDef(
- 'HASH',
- __repr__=interp2app(W_Hash.descr_repr),
- update=interp2app(W_Hash.update),
- copy=interp2app(W_Hash.copy),
- digest=interp2app(W_Hash.digest),
- hexdigest=interp2app(W_Hash.hexdigest),
- #
- digest_size=GetSetProperty(W_Hash.get_digest_size),
- block_size=GetSetProperty(W_Hash.get_block_size),
- name=GetSetProperty(W_Hash.get_name),
-)
-W_Hash.typedef.acceptable_as_base_class = False
-
- at unwrap_spec(name=str, string='bufferstr')
-def new(space, name, string=''):
- w_hash = W_Hash(space, name)
- w_hash.update(space, string)
- return space.wrap(w_hash)
-
-# shortcut functions
-def make_new_hash(name, funcname):
- @func_renamer(funcname)
- @unwrap_spec(string='bufferstr')
- def new_hash(space, string=''):
- return new(space, name, string)
- return new_hash
-
-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='bytes', salt='bytes', 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.newbytes(buf.str(dklen))
diff --git a/pypy/module/_hashlib/test/test_hashlib.py b/pypy/module/_hashlib/test/test_hashlib.py
deleted file mode 100644
--- a/pypy/module/_hashlib/test/test_hashlib.py
+++ /dev/null
@@ -1,100 +0,0 @@
-class AppTestHashlib:
- spaceconfig = {
- "usemodules": ['_hashlib', 'array', 'struct', 'binascii'],
- }
-
- def test_method_names(self):
- import _hashlib
- assert isinstance(_hashlib.openssl_md_meth_names, frozenset)
- assert "md5" in _hashlib.openssl_md_meth_names
-
- def test_simple(self):
- import _hashlib
- assert _hashlib.new('md5').__class__.__name__ == 'HASH'
- assert len(_hashlib.new('md5').hexdigest()) == 32
-
- def test_attributes(self):
- import hashlib
- 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.block_size == expected_block_size
- #
- h.update(b'abc')
- h2 = h.copy()
- h.update(b'def')
- digest = h.digest()
- hexdigest = h.hexdigest()
- h2.update(b'd')
- h2.update(b'ef')
- assert digest == h2.digest()
- assert hexdigest == h2.hexdigest()
- assert len(digest) == h.digest_size
- assert len(hexdigest) == h.digest_size * 2
- c_digest = digest
- c_hexdigest = hexdigest
-
-
- def test_shortcut(self):
- import hashlib
- assert repr(hashlib.md5()).startswith("<md5 HASH object")
-
- def test_uppercase(self):
- import _hashlib
- h = _hashlib.new('MD5')
- assert h.digest_size == 16
- assert len(h.hexdigest()) == 32
-
- def test_buffer(self):
- import _hashlib, array
- b = array.array('b', b'x' * 10)
- h = _hashlib.new('md5', b)
- h.update(b)
- assert h.digest() == _hashlib.openssl_md5(b'x' * 20).digest()
- _hashlib.openssl_sha1(b).digest()
-
- def test_extra_algorithms(self):
- expected_results = {
- "md5": "bb649c83dd1ea5c9d9dec9a18df0ffe9",
- "md4": "c275b8454684ea416b93d7a418b43176",
- "mdc2": None, # XXX find the correct expected value
- "sha": "e2b0a8609b47c58e5d984c9ccfe69f9b654b032b",
- "ripemd160": "cc4a5ce1b3df48aec5d22d1f16b894a0b894eccc",
- "whirlpool": ("1a22b79fe5afda02c63a25927193ed01dc718b74"
- "026e597608ce431f9c3d2c9e74a7350b7fbb7c5d"
- "4effe5d7a31879b8b7a10fd2f544c4ca268ecc6793923583"),
- }
- import _hashlib
- test_string = b"Nobody inspects the spammish repetition"
- for hash_name, expected in sorted(expected_results.items()):
- try:
- m = _hashlib.new(hash_name)
- except ValueError as e:
- print('skipped %s: %s' % (hash_name, e))
- continue
- m.update(test_string)
- got = m.hexdigest()
- assert got and type(got) is str and len(got) % 2 == 0
- 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', b'password', b'salt', 1)
- assert type(out) is bytes
- assert out == '0c60c80f961f0e71f3a9b524af6012062fe037a6'.decode('hex')
- out = pbkdf2_hmac('sha1', b'password', b'salt', 2, None)
- assert out == 'ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957'.decode('hex')
- raises(TypeError, pbkdf2_hmac, 'sha1', 'password', b'salt', 1)
- raises(TypeError, pbkdf2_hmac, 'sha1', b'password', 'salt', 1)
diff --git a/pypy/module/_hashlib/test/test_ztranslation.py b/pypy/module/_hashlib/test/test_ztranslation.py
deleted file mode 100644
--- a/pypy/module/_hashlib/test/test_ztranslation.py
+++ /dev/null
@@ -1,4 +0,0 @@
-from pypy.objspace.fake.checkmodule import checkmodule
-
-def test_checkmodule():
- checkmodule('_hashlib')
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
@@ -534,7 +534,9 @@
"""
rwbuffer = space.getarg_w('w*', w_buffer)
lgt = rwbuffer.getlength()
- if nbytes == 0 or nbytes > lgt:
+ if nbytes < 0:
+ raise oefmt(space.w_ValueError, "negative buffersize in recv_into")
+ if nbytes == 0:
nbytes = lgt
while True:
try:
diff --git a/pypy/module/_socket/test/test_sock_app.py b/pypy/module/_socket/test/test_sock_app.py
--- a/pypy/module/_socket/test/test_sock_app.py
+++ b/pypy/module/_socket/test/test_sock_app.py
@@ -868,6 +868,22 @@
posix.close(fileno)
cli.close()
+ def test_recv_into_params(self):
+ import os
+ import _socket
+ cli = _socket.socket()
+ cli.connect(self.serv.getsockname())
+ fileno, addr = self.serv._accept()
+ os.write(fileno, b"abcdef")
+ #
+ m = memoryview(bytearray(5))
+ raises(ValueError, cli.recv_into, m, -1)
+ raises(ValueError, cli.recv_into, m, 6)
+ cli.recv_into(m,5)
+ assert m.tobytes() == b"abcde"
+ os.close(fileno)
+ cli.close()
+
class AppTestErrno:
spaceconfig = {'usemodules': ['_socket', 'select']}
diff --git a/pypy/module/struct/formatiterator.py b/pypy/module/struct/formatiterator.py
--- a/pypy/module/struct/formatiterator.py
+++ b/pypy/module/struct/formatiterator.py
@@ -109,6 +109,7 @@
self.buf = buf
self.length = buf.getlength()
self.pos = 0
+ self.strides = None
self.result_w = [] # list of wrapped objects
# See above comment on operate.
@@ -126,10 +127,15 @@
self.pos = (self.pos + mask) & ~mask
def finished(self):
- if self.pos != self.length:
+ value = self.pos
+ if self.strides and self.strides[0] < 0:
+ value = -self.pos
+ if value != self.length:
raise StructError("unpack str size too long for format")
def read(self, count):
+ if self.strides:
+ count = self.strides[0]
end = self.pos + count
if end > self.length:
raise StructError("unpack str size too short for format")
@@ -151,5 +157,14 @@
string, pos = self.buf.as_str_and_offset_maybe()
return string, pos+self.pos
- def skip(self, size):
- self.read(size) # XXX, could avoid taking the slice
+ def skip(self, count):
+ # assumption: UnpackFormatIterator only iterates over
+ # flat structures (continous memory) either: forward (index
+ # grows) or reverse
+ if self.strides:
+ assert len(self.strides) == 1
+ count = self.strides[0]
+ end = self.pos + count
+ if end > self.length:
+ raise StructError("unpack str size too short for format")
+ self.pos = end
diff --git a/pypy/objspace/std/memoryobject.py b/pypy/objspace/std/memoryobject.py
--- a/pypy/objspace/std/memoryobject.py
+++ b/pypy/objspace/std/memoryobject.py
@@ -115,8 +115,6 @@
return ''.join(self.copy_buffer())
def copy_buffer(self):
- buf = self.buf
- n_bytes = buf.getlength()
data = []
self._copy_rec(0, data, 0)
return data
@@ -130,7 +128,6 @@
self._copy_base(data,off)
return
- # TODO add a test that has at least 2 dims
for i in range(shape):
self._copy_rec(idim+1,data,off)
off += strides[idim]
@@ -140,18 +137,21 @@
step = shapes[0]
strides = self.getstrides()
itemsize = self.getitemsize()
+ bytesize = self.getlength()
+ copiedbytes = 0
for i in range(step):
bytes = self.buf.getslice(off, off+itemsize, 1, itemsize)
data.append(bytes)
+ copiedbytes += len(bytes)
off += strides[0]
# do notcopy data if the sub buffer is out of bounds
- if off >= self.buf.getlength():
+ if copiedbytes >= bytesize:
break
def getlength(self):
if self.length != -1:
- return self.length // self.itemsize
- return self.buf.getlength() // self.itemsize
+ return self.length
+ return self.buf.getlength()
def descr_tobytes(self, space):
self._check_released(space)
@@ -167,13 +167,20 @@
raise NotImplementedError
elif dim == 1:
itemsize = self.getitemsize()
- return self._tolist(space, buf, buf.getlength() // itemsize, fmt)
+ return self._tolist(space, buf, self.getlength(), itemsize, fmt,
+ self.getstrides())
else:
return self._tolist_rec(space, buf, 0, 0, fmt)
- def _tolist(self, space, buf, count, fmt):
+ def _tolist(self, space, buf, bytecount, itemsize, fmt, strides=None):
# TODO: this probably isn't very fast
+ count = bytecount // itemsize
fmtiter = UnpackFormatIterator(space, buf)
+ # patch the length, necessary buffer might have offset
+ # which leads to wrong length calculation if e.g. the
+ # memoryview is reversed
+ fmtiter.length = bytecount
+ fmtiter.strides = strides
fmtiter.interpret(fmt * count)
return space.newlist(fmtiter.result_w)
@@ -188,12 +195,13 @@
#
if dim >= self.getndim():
bytecount = (stride * dimshape)
- count = bytecount // itemsize
- return self._tolist(space, buf, count, fmt)
+ return self._tolist(space, buf, bytecount, itemsize, fmt, [stride])
items = [None] * dimshape
+ orig_buf = buf
for i in range(dimshape):
- item = self._tolist_rec(space, SubBuffer(buf, start, stride), start, idim+1, fmt)
+ buf = SubBuffer(orig_buf, start, stride)
+ item = self._tolist_rec(space, buf, start, idim+1, fmt)
items[i] = item
start += stride
@@ -212,23 +220,21 @@
while dim < length:
w_obj = w_tuple.getitem(space, dim)
index = space.getindex_w(w_obj, space.w_IndexError)
- start = self.lookup_dimension(space, start, dim, index)
+ shape = self.buf.getshape()
+ strides = self.buf.getstrides()
+ start = self.lookup_dimension(space, shape, strides, start, dim, index)
dim += 1
return start
- def lookup_dimension(self, space, start, dim, index):
- view = self.buf
- shape = view.getshape()
- strides = view.getstrides()
+ def lookup_dimension(self, space, shape, strides, start, dim, index):
nitems = shape[dim]
if index < 0:
index += nitems
if index < 0 or index >= nitems:
raise oefmt(space.w_IndexError,
"index out of bounds on dimension %d", dim+1)
- start += strides[dim] * index
# TODO suboffsets?
- return start
+ return start + strides[dim] * index
def _getitem_tuple_indexed(self, space, w_index):
view = self.buf
@@ -253,50 +259,65 @@
fmtiter.interpret(fmt)
return fmtiter.result_w[0]
+ def _decode_index(self, space, w_index, is_slice):
+ shape = self.getshape()
+ if len(shape) == 0:
+ count = 1
+ else:
+ count = shape[0]
+ return space.decode_index4(w_index, count)
def descr_getitem(self, space, w_index):
self._check_released(space)
if space.isinstance_w(w_index, space.w_tuple):
return self._getitem_tuple_indexed(space, w_index)
-
- start, stop, step, size = space.decode_index4(w_index, self.getlength())
+ is_slice = space.isinstance_w(w_index, space.w_slice)
+ start, stop, step, slicelength = self._decode_index(space, w_index, is_slice)
# ^^^ for a non-slice index, this returns (index, 0, 0, 1)
if step == 0: # index only
itemsize = self.getitemsize()
- if itemsize == 1:
- ch = self.buf.getitem(start)
- return space.newint(ord(ch))
+ dim = self.getndim()
+ if dim == 0:
+ raise oefmt(space.w_TypeError, "invalid indexing of 0-dim memory")
+ elif dim == 1:
+ shape = self.getshape()
+ strides = self.getstrides()
+ idx = self.lookup_dimension(space, shape, strides, 0, 0, start)
+ if itemsize == 1:
+ ch = self.buf.getitem(idx)
+ return space.newint(ord(ch))
+ else:
+ # TODO: this probably isn't very fast
+ buf = SubBuffer(self.buf, idx, itemsize)
+ fmtiter = UnpackFormatIterator(space, buf)
+ fmtiter.length = buf.getlength()
+ fmtiter.interpret(self.format)
+ return fmtiter.result_w[0]
else:
- # TODO: this probably isn't very fast
- buf = SubBuffer(self.buf, start*itemsize, itemsize)
- fmtiter = UnpackFormatIterator(space, buf)
- fmtiter.interpret(self.format)
- return fmtiter.result_w[0]
- elif step == 1:
+ raise oefmt(space.w_NotImplementedError, "multi-dimensional sub-views are not implemented")
+ elif is_slice:
mv = W_MemoryView.copy(self)
- mv.slice(start, step, size)
+ mv.init_slice(start, stop, step, slicelength, 0)
+ mv.init_len()
mv._init_flags()
return mv
+ # multi index is handled at the top of this function
else:
- mv = W_MemoryView.copy(self)
- mv.slice(start, step, size)
- mv.length = mv.bytecount_from_shape()
- mv._init_flags()
- return mv
+ raise TypeError("memoryview: invalid slice key")
- def slice(self, start, step, size):
+ def init_slice(self, start, stop, step, slicelength, dim):
# modifies the buffer, shape and stride to allow step to be > 1
+ self.strides = strides = self.getstrides()[:]
+ self.shape = shape = self.getshape()[:]
+ bytesize = self.getitemsize() * slicelength
+ self.buf = SubBuffer(self.buf, strides[dim] * start, bytesize)
+ shape[dim] = slicelength
+ strides[dim] = strides[dim] * step
# TODO subbuffer
- strides = self.getstrides()[:]
- shape = self.getshape()[:]
- itemsize = self.getitemsize()
- dim = 0
- self.buf = SubBuffer(self.buf, strides[dim] * start, size*step*itemsize)
- shape[dim] = size
- strides[dim] = strides[dim] * step
- self.strides = strides
- self.shape = shape
+
+ def init_len(self):
+ self.length = self.bytecount_from_shape()
def bytecount_from_shape(self):
dim = self.getndim()
@@ -307,10 +328,9 @@
return length * self.getitemsize()
@staticmethod
- def copy(view, buf=None):
+ def copy(view):
# TODO suboffsets
- if buf == None:
- buf = view.buf
+ buf = view.buf
return W_MemoryView(buf, view.getformat(), view.getitemsize(),
view.getndim(), view.getshape()[:], view.getstrides()[:])
@@ -321,11 +341,16 @@
if space.isinstance_w(w_index, space.w_tuple):
raise oefmt(space.w_NotImplementedError, "")
start, stop, step, size = space.decode_index4(w_index, self.getlength())
+ is_slice = space.isinstance_w(w_index, space.w_slice)
+ start, stop, step, slicelength = self._decode_index(space, w_index, is_slice)
itemsize = self.getitemsize()
if step == 0: # index only
+ shape = self.getshape()
+ strides = self.getstrides()
+ idx = self.lookup_dimension(space, shape, strides, 0, 0, start)
if itemsize == 1:
ch = getbytevalue(space, w_obj)
- self.buf.setitem(start, ch)
+ self.buf.setitem(idx, ch)
else:
# TODO: this probably isn't very fast
fmtiter = PackFormatIterator(space, [w_obj], itemsize)
@@ -335,10 +360,10 @@
raise oefmt(space.w_TypeError,
"memoryview: invalid type for format '%s'",
self.format)
- self.buf.setslice(start * itemsize, fmtiter.result.build())
+ self.buf.setslice(idx, fmtiter.result.build())
elif step == 1:
value = space.buffer_w(w_obj, space.BUF_CONTIG_RO)
- if value.getlength() != size * itemsize:
+ if value.getlength() != slicelength * itemsize:
raise oefmt(space.w_ValueError,
"cannot modify size of memoryview object")
self.buf.setslice(start * itemsize, value.as_str())
@@ -354,11 +379,11 @@
src = space.buffer_w(w_obj, space.BUF_CONTIG_RO)
dst_strides = self.getstrides()
dim = 0
- dst = SubBuffer(self.buf, start * itemsize, size * itemsize)
+ dst = SubBuffer(self.buf, start * itemsize, slicelength * itemsize)
src_stride0 = dst_strides[dim]
off = 0
- src_shape0 = size
+ src_shape0 = slicelength
src_stride0 = src.getstrides()[0]
if isinstance(w_obj, W_MemoryView):
src_stride0 = w_obj.getstrides()[0]
@@ -373,11 +398,15 @@
def descr_len(self, space):
self._check_released(space)
- return space.wrap(self.getlength())
+ dim = self.getndim()
+ if dim == 0:
+ return space.newint(1)
+ shape = self.getshape()
+ return space.wrap(shape[0])
def w_get_nbytes(self, space):
self._check_released(space)
- return space.wrap(self.buf.getlength())
+ return space.wrap(self.getlength())
def w_get_format(self, space):
self._check_released(space)
@@ -385,11 +414,11 @@
def w_get_itemsize(self, space):
self._check_released(space)
- return space.wrap(self.itemsize)
+ return space.wrap(self.getitemsize())
def w_get_ndim(self, space):
self._check_released(space)
- return space.wrap(self.buf.getndim())
+ return space.wrap(self.getndim())
def w_is_readonly(self, space):
self._check_released(space)
@@ -397,13 +426,13 @@
def w_get_shape(self, space):
self._check_released(space)
- if self.buf.getndim() == 0:
+ if self.getndim() == 0:
return space.w_None
return space.newtuple([space.wrap(x) for x in self.getshape()])
def w_get_strides(self, space):
self._check_released(space)
- if self.buf.getndim() == 0:
+ if self.getndim() == 0:
return space.w_None
return space.newtuple([space.wrap(x) for x in self.getstrides()])
@@ -615,8 +644,6 @@
return None
def _cast_to_ND(self, space, shape, ndim):
- buf = self.buf
-
self.ndim = ndim
length = self.itemsize
if ndim == 0:
diff --git a/pypy/objspace/std/test/test_memoryobject.py b/pypy/objspace/std/test/test_memoryobject.py
--- a/pypy/objspace/std/test/test_memoryobject.py
+++ b/pypy/objspace/std/test/test_memoryobject.py
@@ -1,4 +1,5 @@
import py
+import pytest
import struct
from pypy.interpreter.baseobjspace import W_Root
from pypy.interpreter.gateway import interp2app
@@ -42,13 +43,13 @@
def test_extended_slice(self):
data = bytearray(b'abcefg')
v = memoryview(data)
- w = v[0:2:2] # failing for now: NotImplementedError
+ w = v[0:2:2]
assert len(w) == 1
assert list(w) == [97]
v[::2] = b'ABC'
assert data == bytearray(eval("b'AbBeCg'"))
- assert v[::2] == b'ABC'
- assert v[::-2] == b'geb'
+ assert v[::2].tobytes() == b'ABC'
+ assert v[::-2].tobytes() == b'geb'
def test_memoryview_attrs(self):
v = memoryview(b"a"*100)
@@ -409,3 +410,33 @@
v = view.cast('h', shape=(3,2))
assert v.tolist() == [[2,3],[4,5],[6,7]]
raises(TypeError, "view.cast('h', shape=(3,3))")
+
+ def test_reversed(self):
+ bytes = b"\x01\x01\x02\x02\x03\x03"
+ view = memoryview(bytes)
+ revlist = list(reversed(view.tolist()))
+ assert view[::-1][0] == 3
+ assert view[::-1][1] == 3
+ assert view[::-1][2] == 2
+ assert view[::-1][3] == 2
+ assert view[::-1][4] == 1
+ assert view[::-1][5] == 1
+ assert view[::-1][-1] == 1
+ assert view[::-1][-2] == 1
+ assert list(reversed(view)) == revlist
+ assert list(reversed(view)) == view[::-1].tolist()
+
+class AppTestMemoryViewReversed(object):
+ spaceconfig = dict(usemodules=['array'])
+ def test_reversed_non_bytes(self):
+ import array
+ items = [1,2,3,9,7,5]
+ formats = ['h']
+ for fmt in formats:
+ bytes = array.array(fmt, items)
+ view = memoryview(bytes)
+ bview = view.cast('b')
+ rview = bview.cast(fmt, shape=(2,3))
+ raises(NotImplementedError, list, reversed(rview))
+ assert rview.tolist() == [[1,2,3],[9,7,5]]
+ assert rview[::-1].tolist() == [[9,7,5], [1,2,3]]
diff --git a/pypy/objspace/std/test/test_typeobject.py b/pypy/objspace/std/test/test_typeobject.py
--- a/pypy/objspace/std/test/test_typeobject.py
+++ b/pypy/objspace/std/test/test_typeobject.py
@@ -667,6 +667,11 @@
b.abc = "awesomer"
assert b.abc == "awesomer"
+ def test_bad_slots(self):
+ raises(TypeError, type, 'A', (), {'__slots__': b'x'})
+ raises(TypeError, type, 'A', (), {'__slots__': 42})
+ raises(TypeError, type, 'A', (), {'__slots__': '2_x'})
+
def test_base_attr(self):
# check the '__base__'
class A(object):
@@ -936,6 +941,22 @@
else:
assert False
+ def test_qualname(self):
+ A = type('A', (), {'__qualname__': 'B.C'})
+ assert A.__name__ == 'A'
+ assert A.__qualname__ == 'B.C'
+ raises(TypeError, type, 'A', (), {'__qualname__': b'B'})
+ assert A.__qualname__ == 'B.C'
+
+ A.__qualname__ = 'D.E'
+ assert A.__name__ == 'A'
+ assert A.__qualname__ == 'D.E'
+
+ C = type('C', (), {})
+ C.__name__ = 'A'
+ assert C.__name__ == 'A'
+ assert C.__qualname__ == 'C'
+
def test_compare(self):
class A(object):
pass
diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py
--- a/pypy/objspace/std/typeobject.py
+++ b/pypy/objspace/std/typeobject.py
@@ -166,7 +166,7 @@
overridetypedef=None, force_new_layout=False):
self.space = space
self.name = name
- self.qualname = None
+ self.qualname = name.decode('utf-8')
self.bases_w = bases_w
self.dict_w = dict_w
self.hasdict = False
@@ -545,7 +545,7 @@
return result.decode('utf-8')
def getqualname(self, space):
- return self.qualname or self.getname(space)
+ return self.qualname
def add_subclass(self, w_subclass):
space = self.space
@@ -1057,6 +1057,14 @@
w_self.weakrefable = w_self.weakrefable or w_base.weakrefable
return hasoldstylebase
+def slot_w(space, w_name):
+ from pypy.objspace.std.unicodeobject import _isidentifier
+ if not space.isinstance_w(w_name, space.w_text):
+ raise oefmt(space.w_TypeError,
+ "__slots__ items must be strings, not '%T'", w_name)
+ if not _isidentifier(w_name._value):
+ raise oefmt(space.w_TypeError, "__slots__ must be identifiers")
+ return w_name.identifier_w(space)
def create_all_slots(w_self, hasoldstylebase, w_bestbase, force_new_layout):
from pypy.objspace.std.listobject import StringSort
@@ -1073,13 +1081,12 @@
wantdict = False
wantweakref = False
w_slots = dict_w['__slots__']
- if (space.isinstance_w(w_slots, space.w_str) or
- space.isinstance_w(w_slots, space.w_unicode)):
+ if space.isinstance_w(w_slots, space.w_text):
slot_names_w = [w_slots]
else:
slot_names_w = space.unpackiterable(w_slots)
for w_slot_name in slot_names_w:
- slot_name = space.str_w(w_slot_name)
+ slot_name = slot_w(space, w_slot_name)
if slot_name == '__dict__':
if wantdict or w_bestbase.hasdict:
raise oefmt(space.w_TypeError,
@@ -1124,8 +1131,6 @@
def create_slot(w_self, slot_name, index_next_extra_slot):
space = w_self.space
- if not valid_slot_name(slot_name):
- raise oefmt(space.w_TypeError, "__slots__ must be identifiers")
# create member
slot_name = mangle(slot_name, w_self.name)
if slot_name not in w_self.dict_w:
@@ -1156,14 +1161,6 @@
w_self.space.wrap(weakref_descr))
w_self.weakrefable = True
-def valid_slot_name(slot_name):
- if len(slot_name) == 0 or slot_name[0].isdigit():
- return False
- for c in slot_name:
- if not c.isalnum() and c != '_':
- return False
- return True
-
def setup_user_defined_type(w_self, force_new_layout):
if len(w_self.bases_w) == 0:
w_self.bases_w = [w_self.space.w_object]
diff --git a/pypy/tool/build_cffi_imports.py b/pypy/tool/build_cffi_imports.py
--- a/pypy/tool/build_cffi_imports.py
+++ b/pypy/tool/build_cffi_imports.py
@@ -18,6 +18,7 @@
"lzma": "_lzma_build.py",
"_decimal": "_decimal_build.py",
"ssl": "_ssl_build.py",
+ # hashlib does not need to be built! It uses API calls from ssl
"xx": None, # for testing: 'None' should be completely ignored
}
More information about the pypy-commit
mailing list