[pypy-commit] pypy refactor-str-types: hg merge default
Manuel Jacob
noreply at buildbot.pypy.org
Mon Jan 13 12:11:32 CET 2014
Author: Manuel Jacob
Branch: refactor-str-types
Changeset: r68631:1dfbad2cbd56
Date: 2014-01-13 11:05 +0100
http://bitbucket.org/pypy/pypy/changeset/1dfbad2cbd56/
Log: hg merge default
diff too long, truncating to 2000 out of 12023 lines
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -28,7 +28,7 @@
DEALINGS IN THE SOFTWARE.
-PyPy Copyright holders 2003-2013
+PyPy Copyright holders 2003-2014
-----------------------------------
Except when otherwise stated (look for LICENSE files or information at
diff --git a/lib-python/2.7/ctypes/__init__.py b/lib-python/2.7/ctypes/__init__.py
--- a/lib-python/2.7/ctypes/__init__.py
+++ b/lib-python/2.7/ctypes/__init__.py
@@ -371,10 +371,9 @@
self._handle = handle
def __repr__(self):
- return "<%s '%s', handle %r at %x>" % \
- (self.__class__.__name__, self._name,
- (self._handle),
- id(self) & (_sys.maxint*2 + 1))
+ return "<%s '%s', handle %r at 0x%x>" % (
+ self.__class__.__name__, self._name, self._handle,
+ id(self) & (_sys.maxint * 2 + 1))
def __getattr__(self, name):
diff --git a/lib-python/2.7/ctypes/test/test_python_api.py b/lib-python/2.7/ctypes/test/test_python_api.py
--- a/lib-python/2.7/ctypes/test/test_python_api.py
+++ b/lib-python/2.7/ctypes/test/test_python_api.py
@@ -73,6 +73,7 @@
del pyobj
self.assertEqual(grc(s), ref)
+ @xfail
def test_PyOS_snprintf(self):
PyOS_snprintf = pythonapi.PyOS_snprintf
PyOS_snprintf.argtypes = POINTER(c_char), c_size_t, c_char_p
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
@@ -993,7 +993,7 @@
try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True)
try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL)
try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED)
- try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True)
+ try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, False)
try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False)
try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False)
diff --git a/lib-python/conftest.py b/lib-python/conftest.py
--- a/lib-python/conftest.py
+++ b/lib-python/conftest.py
@@ -109,7 +109,7 @@
RegrTest('test_asynchat.py', usemodules='select fcntl'),
RegrTest('test_asyncore.py', usemodules='select fcntl'),
RegrTest('test_atexit.py', core=True),
- RegrTest('test_audioop.py', skip="unsupported extension module"),
+ RegrTest('test_audioop.py', skip="incomplete module"),
RegrTest('test_augassign.py', core=True),
RegrTest('test_base64.py', usemodules='struct'),
RegrTest('test_bastion.py'),
diff --git a/lib_pypy/_ctypes/function.py b/lib_pypy/_ctypes/function.py
--- a/lib_pypy/_ctypes/function.py
+++ b/lib_pypy/_ctypes/function.py
@@ -328,21 +328,23 @@
raise ValueError(
"native COM method call without 'this' parameter"
)
- thisarg = cast(args[0], POINTER(POINTER(c_void_p)))
- keepalives, newargs, argtypes, outargs = self._convert_args(argtypes,
- args[1:], kwargs)
- newargs.insert(0, args[0].value)
+ thisvalue = args.pop(0)
+ thisarg = cast(thisvalue, POINTER(POINTER(c_void_p)))
+ keepalives, newargs, argtypes, outargs, errcheckargs = (
+ self._convert_args(argtypes, args, kwargs))
+ args.insert(0, thisvalue)
+ newargs.insert(0, thisvalue.value)
argtypes.insert(0, c_void_p)
else:
thisarg = None
- keepalives, newargs, argtypes, outargs = self._convert_args(argtypes,
- args, kwargs)
+ keepalives, newargs, argtypes, outargs, errcheckargs = (
+ self._convert_args(argtypes, args, kwargs))
funcptr = self._getfuncptr(argtypes, self._restype_, thisarg)
result = self._call_funcptr(funcptr, *newargs)
- result = self._do_errcheck(result, args)
+ result, forced = self._do_errcheck(result, errcheckargs)
- if not outargs:
+ if not outargs or forced:
return result
from ctypes import c_void_p
@@ -377,22 +379,22 @@
set_last_error(tmp)
#
try:
- return self._build_result(self._restype_, result, newargs)
+ return self._build_result(self._restype_, result)
finally:
funcptr.free_temp_buffers()
def _do_errcheck(self, result, args):
# The 'errcheck' protocol
if self._errcheck_:
- v = self._errcheck_(result, self, args)
+ v = self._errcheck_(result, self, tuple(args))
# If the errcheck funtion failed, let it throw
# If the errcheck function returned newargs unchanged,
# continue normal processing.
# If the errcheck function returned something else,
# use that as result.
if v is not args:
- return v
- return result
+ return v, True
+ return result, False
def _getfuncptr_fromaddress(self, argtypes, restype):
address = self._get_address()
@@ -495,16 +497,16 @@
newargtypes = []
total = len(args)
paramflags = self._paramflags
- inargs_idx = 0
if not paramflags and total < len(argtypes):
raise TypeError("not enough arguments")
- for i, argtype in enumerate(argtypes):
- flag = 0
- name = None
- defval = marker
- if paramflags:
+ if paramflags:
+ errcheckargs = []
+ inargs_idx = 0
+ for i, argtype in enumerate(argtypes):
+ flag = 0
+ defval = marker
paramflag = paramflags[i]
paramlen = len(paramflag)
name = None
@@ -519,6 +521,7 @@
val = defval
if val is marker:
val = 0
+ errcheckargs.append(val)
keepalive, newarg, newargtype = self._conv_param(argtype, val)
keepalives.append(keepalive)
newargs.append(newarg)
@@ -536,27 +539,31 @@
raise TypeError("required argument '%s' missing" % name)
else:
raise TypeError("not enough arguments")
+ errcheckargs.append(val)
keepalive, newarg, newargtype = self._conv_param(argtype, val)
keepalives.append(keepalive)
newargs.append(newarg)
newargtypes.append(newargtype)
elif flag == PARAMFLAG_FOUT:
if defval is not marker:
- outargs.append(defval)
+ val = defval
keepalive, newarg, newargtype = self._conv_param(argtype, defval)
else:
import ctypes
val = argtype._type_()
- outargs.append(val)
keepalive = None
newarg = ctypes.byref(val)
newargtype = type(newarg)
+ errcheckargs.append(val)
+ outargs.append(val)
keepalives.append(keepalive)
newargs.append(newarg)
newargtypes.append(newargtype)
else:
raise ValueError("paramflag %d not yet implemented" % flag)
- else:
+ else:
+ errcheckargs = args
+ for i, argtype in enumerate(argtypes):
try:
keepalive, newarg, newargtype = self._conv_param(argtype, args[i])
except (UnicodeError, TypeError, ValueError), e:
@@ -564,7 +571,6 @@
keepalives.append(keepalive)
newargs.append(newarg)
newargtypes.append(newargtype)
- inargs_idx += 1
if len(newargs) < len(args):
extra = args[len(newargs):]
@@ -576,7 +582,7 @@
keepalives.append(keepalive)
newargs.append(newarg)
newargtypes.append(newargtype)
- return keepalives, newargs, newargtypes, outargs
+ return keepalives, newargs, newargtypes, outargs, errcheckargs
@staticmethod
def _is_primitive(argtype):
@@ -601,7 +607,7 @@
retval = restype._CData_retval(buf)
return retval
- def _build_result(self, restype, result, argsandobjs):
+ def _build_result(self, restype, result):
"""Build the function result:
If there is no OUT parameter, return the actual function result
If there is one OUT parameter, return it
@@ -611,11 +617,6 @@
# i.e. an array of ints. Now it takes a result, which is already a
# python object. All places that do "resbuffer[0]" should check that
# result is actually an int and just use it.
- #
- # Also, argsandobjs used to be "args" in __call__, now it's "newargs"
- # (i.e., the already unwrapped objects). It's used only when we have a
- # PARAMFLAG_FOUT and it's probably wrong, I'll fix it when I find a
- # failing test
retval = None
@@ -704,7 +705,7 @@
funcptr = self._getfuncptr(argtypes, restype, thisarg)
try:
result = self._call_funcptr(funcptr, *args)
- result = self._do_errcheck(result, args)
+ result, _ = self._do_errcheck(result, args)
except (TypeError, ArgumentError, UnicodeDecodeError):
assert self._slowpath_allowed
return CFuncPtr.__call__(self, *args)
diff --git a/lib_pypy/_pypy_testcapi.py b/lib_pypy/_pypy_testcapi.py
--- a/lib_pypy/_pypy_testcapi.py
+++ b/lib_pypy/_pypy_testcapi.py
@@ -33,14 +33,13 @@
# set link options
output_filename = modulename + _get_c_extension_suffix()
if sys.platform == 'win32':
- # XXX libpypy-c.lib is currently not installed automatically
- library = os.path.join(thisdir, '..', 'include', 'libpypy-c')
+ # XXX pyconfig.h uses a pragma to link to the import library,
+ # which is currently python27.lib
+ library = os.path.join(thisdir, '..', 'include', 'python27')
if not os.path.exists(library + '.lib'):
- #For a nightly build
- library = os.path.join(thisdir, '..', 'include', 'python27')
- if not os.path.exists(library + '.lib'):
- # For a local translation
- library = os.path.join(thisdir, '..', 'pypy', 'goal', 'libpypy-c')
+ # For a local translation or nightly build
+ library = os.path.join(thisdir, '..', 'pypy', 'goal', 'python27')
+ assert os.path.exists(library + '.lib'),'Could not find import library "%s"' % library
libraries = [library, 'oleaut32']
extra_ldargs = ['/MANIFEST', # needed for VC10
'/EXPORT:init' + modulename]
diff --git a/lib_pypy/_sha.py b/lib_pypy/_sha.py
--- a/lib_pypy/_sha.py
+++ b/lib_pypy/_sha.py
@@ -115,14 +115,14 @@
]
class sha:
- "An implementation of the MD5 hash function in pure Python."
+ "An implementation of the SHA hash function in pure Python."
digest_size = digestsize = 20
- block_size = 1
+ block_size = 512 // 8
def __init__(self):
"Initialisation."
-
+
# Initial message length in bits(!).
self.length = 0
self.count = [0, 0]
@@ -209,7 +209,7 @@
self.H2 = (self.H2 + C) & 0xffffffff
self.H3 = (self.H3 + D) & 0xffffffff
self.H4 = (self.H4 + E) & 0xffffffff
-
+
# Down from here all methods follow the Python Standard Library
# API of the sha module.
@@ -295,13 +295,13 @@
_long2bytesBigEndian(self.H3, 4) + \
_long2bytesBigEndian(self.H4, 4)
- self.H0 = H0
- self.H1 = H1
+ self.H0 = H0
+ self.H1 = H1
self.H2 = H2
self.H3 = H3
self.H4 = H4
- self.input = input
- self.count = count
+ self.input = input
+ self.count = count
return digest
diff --git a/lib_pypy/_sqlite3.py b/lib_pypy/_sqlite3.py
--- a/lib_pypy/_sqlite3.py
+++ b/lib_pypy/_sqlite3.py
@@ -330,6 +330,14 @@
# SQLite version information
sqlite_version = str(_ffi.string(_lib.sqlite3_libversion()).decode('ascii'))
+_STMT_TYPE_UPDATE = 0
+_STMT_TYPE_DELETE = 1
+_STMT_TYPE_INSERT = 2
+_STMT_TYPE_REPLACE = 3
+_STMT_TYPE_OTHER = 4
+_STMT_TYPE_SELECT = 5
+_STMT_TYPE_INVALID = 6
+
class Error(StandardError):
pass
@@ -992,13 +1000,18 @@
self.__statement = self.__connection._statement_cache.get(sql)
if self.__connection._isolation_level is not None:
- if self.__statement._type in ("UPDATE", "DELETE", "INSERT", "REPLACE"):
+ if self.__statement._type in (
+ _STMT_TYPE_UPDATE,
+ _STMT_TYPE_DELETE,
+ _STMT_TYPE_INSERT,
+ _STMT_TYPE_REPLACE
+ ):
if not self.__connection._in_transaction:
self.__connection._begin()
- elif self.__statement._type == "OTHER":
+ elif self.__statement._type == _STMT_TYPE_OTHER:
if self.__connection._in_transaction:
self.__connection.commit()
- elif self.__statement._type == "SELECT":
+ elif self.__statement._type == _STMT_TYPE_SELECT:
if multiple:
raise ProgrammingError("You cannot execute SELECT "
"statements in executemany().")
@@ -1021,12 +1034,17 @@
self.__statement._reset()
raise self.__connection._get_exception(ret)
- if self.__statement._type in ("UPDATE", "DELETE", "INSERT", "REPLACE"):
+ if self.__statement._type in (
+ _STMT_TYPE_UPDATE,
+ _STMT_TYPE_DELETE,
+ _STMT_TYPE_INSERT,
+ _STMT_TYPE_REPLACE
+ ):
if self.__rowcount == -1:
self.__rowcount = 0
self.__rowcount += _lib.sqlite3_changes(self.__connection._db)
- if not multiple and self.__statement._type == "INSERT":
+ if not multiple and self.__statement._type == _STMT_TYPE_INSERT:
self.__lastrowid = _lib.sqlite3_last_insert_rowid(self.__connection._db)
else:
self.__lastrowid = None
@@ -1176,11 +1194,19 @@
first_word = sql.lstrip().split(" ")[0].upper()
if first_word == "":
- self._type = "INVALID"
- elif first_word in ("SELECT", "INSERT", "UPDATE", "DELETE", "REPLACE"):
- self._type = first_word
+ self._type = _STMT_TYPE_INVALID
+ elif first_word == "SELECT":
+ self._type = _STMT_TYPE_SELECT
+ elif first_word == "INSERT":
+ self._type = _STMT_TYPE_INSERT
+ elif first_word == "UPDATE":
+ self._type = _STMT_TYPE_UPDATE
+ elif first_word == "DELETE":
+ self._type = _STMT_TYPE_DELETE
+ elif first_word == "REPLACE":
+ self._type = _STMT_TYPE_REPLACE
else:
- self._type = "OTHER"
+ self._type = _STMT_TYPE_OTHER
if isinstance(sql, unicode):
sql = sql.encode('utf-8')
@@ -1193,7 +1219,7 @@
if ret == _lib.SQLITE_OK and not self._statement:
# an empty statement, work around that, as it's the least trouble
- self._type = "SELECT"
+ self._type = _STMT_TYPE_SELECT
c_sql = _ffi.new("char[]", b"select 42")
ret = _lib.sqlite3_prepare_v2(self.__con._db, c_sql, -1,
statement_star, next_char)
@@ -1312,7 +1338,12 @@
raise ValueError("parameters are of unsupported type")
def _get_description(self):
- if self._type in ("INSERT", "UPDATE", "DELETE", "REPLACE"):
+ if self._type in (
+ _STMT_TYPE_INSERT,
+ _STMT_TYPE_UPDATE,
+ _STMT_TYPE_DELETE,
+ _STMT_TYPE_REPLACE
+ ):
return None
desc = []
for i in xrange(_lib.sqlite3_column_count(self._statement)):
diff --git a/lib_pypy/audioop.py b/lib_pypy/audioop.py
new file mode 100644
--- /dev/null
+++ b/lib_pypy/audioop.py
@@ -0,0 +1,29 @@
+
+import struct
+
+
+class error(Exception):
+ pass
+
+
+def _check_size(size):
+ if size != 1 and size != 2 and size != 4:
+ raise error("Size should be 1, 2 or 4")
+
+
+def _check_params(length, size):
+ _check_size(size)
+ if length % size != 0:
+ raise error("not a whole number of frames")
+
+
+def getsample(cp, size, i):
+ _check_params(len(cp), size)
+ if not (0 <= i < len(cp) / size):
+ raise error("Index out of range")
+ if size == 1:
+ return struct.unpack_from("B", buffer(cp)[i:])[0]
+ elif size == 2:
+ return struct.unpack_from("H", buffer(cp)[i * 2:])[0]
+ elif size == 4:
+ return struct.unpack_from("I", buffer(cp)[i * 4:])[0]
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,5 +4,5 @@
from .api import FFI, CDefError, FFIError
from .ffiplatform import VerificationError, VerificationMissing
-__version__ = "0.8"
-__version_info__ = (0, 8)
+__version__ = "0.8.1"
+__version_info__ = (0, 8, 1)
diff --git a/lib_pypy/datetime.py b/lib_pypy/datetime.py
--- a/lib_pypy/datetime.py
+++ b/lib_pypy/datetime.py
@@ -878,7 +878,6 @@
month = self._month
if day is None:
day = self._day
- year, month, day = _check_date_fields(year, month, day)
return date(year, month, day)
# Comparisons of date objects with other.
@@ -1389,8 +1388,6 @@
microsecond = self.microsecond
if tzinfo is True:
tzinfo = self.tzinfo
- hour, minute, second, microsecond = _check_time_fields(hour, minute, second, microsecond)
- _check_tzinfo_arg(tzinfo)
return time(hour, minute, second, microsecond, tzinfo)
def __nonzero__(self):
@@ -1608,9 +1605,6 @@
microsecond = self.microsecond
if tzinfo is True:
tzinfo = self.tzinfo
- year, month, day = _check_date_fields(year, month, day)
- hour, minute, second, microsecond = _check_time_fields(hour, minute, second, microsecond)
- _check_tzinfo_arg(tzinfo)
return datetime(year, month, day, hour, minute, second, microsecond,
tzinfo)
diff --git a/lib_pypy/pyrepl/simple_interact.py b/lib_pypy/pyrepl/simple_interact.py
--- a/lib_pypy/pyrepl/simple_interact.py
+++ b/lib_pypy/pyrepl/simple_interact.py
@@ -63,3 +63,6 @@
except KeyboardInterrupt:
console.write("\nKeyboardInterrupt\n")
console.resetbuffer()
+ except MemoryError:
+ console.write("\nMemoryError\n")
+ console.resetbuffer()
diff --git a/pypy/doc/conf.py b/pypy/doc/conf.py
--- a/pypy/doc/conf.py
+++ b/pypy/doc/conf.py
@@ -38,7 +38,7 @@
# General information about the project.
project = u'PyPy'
-copyright = u'2013, The PyPy Project'
+copyright = u'2014, The PyPy Project'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
@@ -47,7 +47,7 @@
# The short X.Y version.
version = '2.2'
# The full version, including alpha/beta/rc tags.
-release = '2.2.0'
+release = '2.2.1'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst
--- a/pypy/doc/cpython_differences.rst
+++ b/pypy/doc/cpython_differences.rst
@@ -83,7 +83,7 @@
_winreg
-* Supported by being rewritten in pure Python (possibly using ``ctypes``):
+* Supported by being rewritten in pure Python (possibly using ``cffi``):
see the `lib_pypy/`_ directory. Examples of modules that we
support this way: ``ctypes``, ``cPickle``, ``cmath``, ``dbm``, ``datetime``...
Note that some modules are both in there and in the list above;
@@ -316,5 +316,4 @@
type and vice versa. For builtin types, a dictionary will be returned that
cannot be changed (but still looks and behaves like a normal dictionary).
-
.. include:: _ref.txt
diff --git a/pypy/doc/ctypes-implementation.rst b/pypy/doc/ctypes-implementation.rst
--- a/pypy/doc/ctypes-implementation.rst
+++ b/pypy/doc/ctypes-implementation.rst
@@ -72,7 +72,13 @@
Here is a list of the limitations and missing features of the
current implementation:
-* No support for ``PyXxx`` functions from ``libpython``, for obvious reasons.
+* ``ctypes.pythonapi`` lets you access the CPython C API emulation layer
+ of PyPy, at your own risks and without doing anything sensible about
+ the GIL. Since PyPy 2.3, these functions are also named with an extra
+ "Py", for example ``PyPyInt_FromLong()``. Basically, don't use this,
+ but it might more or less work in simple cases if you do. (Obviously,
+ assuming the PyObject pointers you get have any particular fields in
+ any particular order is just going to crash.)
* We copy Python strings instead of having pointers to raw buffers
diff --git a/pypy/doc/extending.rst b/pypy/doc/extending.rst
--- a/pypy/doc/extending.rst
+++ b/pypy/doc/extending.rst
@@ -5,119 +5,68 @@
This document tries to explain how to interface the PyPy python interpreter
with any external library.
-Note: We try to describe state-of-the art, but it
-might fade out of date as this is the front on which things are changing
-in pypy rapidly.
+Right now, there are the following possibilities of providing
+third-party modules for the PyPy python interpreter (in order of
+usefulness):
-Possibilities
-=============
+* Write them in pure Python and use CFFI_.
-Right now, there are three possibilities of providing third-party modules
-for the PyPy python interpreter (in order of usefulness):
+* Write them in pure Python and use ctypes_.
-* Write them in pure python and use ctypes, see ctypes_
- section
+* Write them in C++ and bind them through Reflex_.
-* Write them in pure python and use direct libffi low-level bindings, See
- \_ffi_ module description.
+* Write them in as `RPython mixed modules`_.
-* Write them in RPython as mixedmodule_, using *rffi* as bindings.
-* Write them in C++ and bind them through Reflex_
+CFFI
+====
-.. _ctypes: #CTypes
-.. _\_ffi: #LibFFI
-.. _mixedmodule: #Mixed Modules
+CFFI__ is the recommended way. It is a way to write pure Python code
+that accesses C libraries. The idea is to support either ABI- or
+API-level access to C --- so that you can sanely access C libraries
+without depending on details like the exact field order in the C
+structures or the numerical value of all the constants. It works on
+both CPython (as a separate ``pip install cffi``) and on PyPy, where it
+is included by default.
+
+PyPy's JIT does a quite reasonable job on the Python code that call C
+functions or manipulate C pointers with CFFI. (As of PyPy 2.2.1, it
+could still be improved, but is already good.)
+
+See the documentation here__.
+
+.. __: http://cffi.readthedocs.org/
+.. __: http://cffi.readthedocs.org/
+
CTypes
======
-The ctypes module in PyPy is ready to use.
-It's goal is to be as-compatible-as-possible with the
-`CPython ctypes`_ version. Right now it's able to support large examples,
-such as pyglet. PyPy is planning to have a 100% compatible ctypes
-implementation, without the CPython C-level API bindings (so it is very
-unlikely that direct object-manipulation trickery through this API will work).
+The goal of the ctypes module of PyPy is to be as compatible as possible
+with the `CPython ctypes`_ version. It works for large examples, such
+as pyglet. PyPy's implementation is not strictly 100% compatible with
+CPython, but close enough for most cases.
-We also provide a `ctypes-configure`_ for overcoming the platform dependencies,
-not relying on the ctypes codegen. This tool works by querying gcc about
-platform-dependent details (compiling small snippets of C code and running
-them), so it'll benefit not pypy-related ctypes-based modules as well.
+We also used to provide ``ctypes-configure`` for some API-level access.
+This is now viewed as a precursor of CFFI, which you should use instead.
+More (but older) information is available here__.
+Also, ctypes' performance is not as good as CFFI's.
-ctypes call are optimized by the JIT and the resulting machine code contains a
-direct call to the target C function. However, due to the very dynamic nature
-of ctypes, some overhead over a bare C call is still present, in particular to
-check/convert the types of the parameters. Moreover, even if most calls are
-optimized, some cannot and thus need to follow the slow path, not optimized by
-the JIT.
+.. _`CPython ctypes`: http://docs.python.org/library/ctypes.html
+.. __: ctypes-implementation.html
-.. _`ctypes-configure`: ctypes-implementation.html#ctypes-configure
-.. _`CPython ctypes`: http://docs.python.org/library/ctypes.html
+PyPy implements ctypes as pure Python code around two built-in modules
+called ``_ffi`` and ``_rawffi``, which give a very low-level binding to
+the C library libffi_. Nowadays it is not recommended to use directly
+these two modules.
-Pros
-----
+.. _libffi: http://sourceware.org/libffi/
-Stable, CPython-compatible API. Most calls are fast, optimized by JIT.
-
-Cons
-----
-
-Problems with platform-dependency (although we partially solve
-those). Although the JIT optimizes ctypes calls, some overhead is still
-present. The slow-path is very slow.
-
-
-LibFFI
-======
-
-Mostly in order to be able to write a ctypes module, we developed a very
-low-level libffi bindings called ``_ffi``. (libffi is a C-level library for dynamic calling,
-which is used by CPython ctypes). This library provides stable and usable API,
-although it's API is a very low-level one. It does not contain any
-magic. It is also optimized by the JIT, but has much less overhead than ctypes.
-
-Pros
-----
-
-It Works. Probably more suitable for a delicate code where ctypes magic goes
-in a way. All calls are optimized by the JIT, there is no slow path as in
-ctypes.
-
-Cons
-----
-
-It combines disadvantages of using ctypes with disadvantages of using mixed
-modules. CPython-incompatible API, very rough and low-level.
-
-Mixed Modules
-=============
-
-This is the most advanced and powerful way of writing extension modules.
-It has some serious disadvantages:
-
-* a mixed module needs to be written in RPython, which is far more
- complicated than Python (XXX link)
-
-* due to lack of separate compilation (as of July 2011), each
- compilation-check requires to recompile whole PyPy python interpreter,
- which takes 0.5-1h. We plan to solve this at some point in near future.
-
-* although rpython is a garbage-collected language, the border between
- C and RPython needs to be managed by hand (each object that goes into the
- C level must be explicitly freed).
-
-Some documentation is available `here`_
-
-.. _`here`: rffi.html
-
-XXX we should provide detailed docs about lltype and rffi, especially if we
- want people to follow that way.
Reflex
======
-This method is still experimental and is being exercised on a branch,
-`reflex-support`_, which adds the `cppyy`_ module.
+This method is still experimental. It adds the `cppyy`_ module.
The method works by using the `Reflex package`_ to provide reflection
information of the C++ code, which is then used to automatically generate
bindings at runtime.
@@ -168,3 +117,15 @@
to work around it in python or with a C++ helper function.
Although Reflex works on various platforms, the bindings with PyPy have only
been tested on Linux.
+
+
+RPython Mixed Modules
+=====================
+
+This is the internal way to write built-in extension modules in PyPy.
+It cannot be used by any 3rd-party module: the extension modules are
+*built-in*, not independently loadable DLLs.
+
+This is reserved for special cases: it gives direct access to e.g. the
+details of the JIT, allowing us to tweak its interaction with user code.
+This is how the numpy module is being developed.
diff --git a/pypy/doc/extradoc.rst b/pypy/doc/extradoc.rst
--- a/pypy/doc/extradoc.rst
+++ b/pypy/doc/extradoc.rst
@@ -72,13 +72,13 @@
.. _bibtex: https://bitbucket.org/pypy/extradoc/raw/tip/talk/bibtex.bib
.. _`Runtime Feedback in a Meta-Tracing JIT for Efficient Dynamic Languages`: https://bitbucket.org/pypy/extradoc/raw/extradoc/talk/icooolps2011/jit-hints.pdf
-.. _`Allocation Removal by Partial Evaluation in a Tracing JIT`: http://codespeak.net/svn/pypy/extradoc/talk/pepm2011/bolz-allocation-removal.pdf
-.. _`Towards a Jitting VM for Prolog Execution`: http://www.stups.uni-duesseldorf.de/publications/bolz-prolog-jit.pdf
+.. _`Allocation Removal by Partial Evaluation in a Tracing JIT`: https://bitbucket.org/pypy/extradoc/raw/extradoc/talk/pepm2011/bolz-allocation-removal.pdf
+.. _`Towards a Jitting VM for Prolog Execution`: http://www.stups.uni-duesseldorf.de/mediawiki/images/a/a7/Pub-BoLeSch2010.pdf
.. _`High performance implementation of Python for CLI/.NET with JIT compiler generation for dynamic languages`: http://buildbot.pypy.org/misc/antocuni-thesis.pdf
.. _`How to *not* write Virtual Machines for Dynamic Languages`: https://bitbucket.org/pypy/extradoc/raw/tip/talk/dyla2007/dyla.pdf
.. _`Tracing the Meta-Level: PyPy's Tracing JIT Compiler`: https://bitbucket.org/pypy/extradoc/raw/tip/talk/icooolps2009/bolz-tracing-jit.pdf
.. _`Faster than C#: Efficient Implementation of Dynamic Languages on .NET`: https://bitbucket.org/pypy/extradoc/raw/tip/talk/icooolps2009-dotnet/cli-jit.pdf
-.. _`Automatic JIT Compiler Generation with Runtime Partial Evaluation`: http://www.stups.uni-duesseldorf.de/thesis/final-master.pdf
+.. _`Automatic JIT Compiler Generation with Runtime Partial Evaluation`: http://wwwold.cobra.cs.uni-duesseldorf.de/thesis/final-master.pdf
.. _`RPython: A Step towards Reconciling Dynamically and Statically Typed OO Languages`: http://www.disi.unige.it/person/AnconaD/papers/Recent_abstracts.html#AACM-DLS07
.. _`EU Reports`: index-report.html
.. _`Hardware Transactional Memory Support for Lightweight Dynamic Language Evolution`: http://sabi.net/nriley/pubs/dls6-riley.pdf
diff --git a/pypy/doc/faq.rst b/pypy/doc/faq.rst
--- a/pypy/doc/faq.rst
+++ b/pypy/doc/faq.rst
@@ -444,7 +444,7 @@
So the position of the core PyPy developers is that if anyone wants to
make an N+1'th attempt with LLVM, they are welcome, and will be happy to
provide help in the IRC channel, but they are left with the burden of proof
-that it works.
+that (a) it works and (b) it gives important benefits.
----------------------
How do I compile PyPy?
diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst
--- a/pypy/doc/index.rst
+++ b/pypy/doc/index.rst
@@ -40,7 +40,7 @@
* `FAQ`_: some frequently asked questions.
-* `Release 2.2.0`_: the latest official release
+* `Release 2.2.1`_: the latest official release
* `PyPy Blog`_: news and status info about PyPy
@@ -110,7 +110,7 @@
.. _`Getting Started`: getting-started.html
.. _`Papers`: extradoc.html
.. _`Videos`: video-index.html
-.. _`Release 2.2.0`: http://pypy.org/download.html
+.. _`Release 2.2.1`: http://pypy.org/download.html
.. _`speed.pypy.org`: http://speed.pypy.org
.. _`RPython toolchain`: translation.html
.. _`potential project ideas`: project-ideas.html
diff --git a/pypy/doc/release-2.2.1.rst b/pypy/doc/release-2.2.1.rst
new file mode 100644
--- /dev/null
+++ b/pypy/doc/release-2.2.1.rst
@@ -0,0 +1,47 @@
+=======================================
+PyPy 2.2.1 - Incrementalism.1
+=======================================
+
+We're pleased to announce PyPy 2.2.1, which targets version 2.7.3 of the Python
+language. This is a bugfix release over 2.2.
+
+You can download the PyPy 2.2.1 release here:
+
+ http://pypy.org/download.html
+
+What is PyPy?
+=============
+
+PyPy is a very compliant Python interpreter, almost a drop-in replacement for
+CPython 2.7. It's fast (`pypy 2.2 and cpython 2.7.2`_ performance comparison)
+due to its integrated tracing JIT compiler.
+
+This release supports x86 machines running Linux 32/64, Mac OS X 64, Windows
+32, or ARM (ARMv6 or ARMv7, with VFPv3).
+
+Work on the native Windows 64 is still stalling, we would welcome a volunteer
+to handle that.
+
+.. _`pypy 2.2 and cpython 2.7.2`: http://speed.pypy.org
+
+Highlights
+==========
+
+This is a bugfix release. The most important bugs fixed are:
+
+* an issue in sockets' reference counting emulation, showing up
+ notably when using the ssl module and calling ``makefile()``.
+
+* Tkinter support on Windows.
+
+* If sys.maxunicode==65535 (on Windows and maybe OS/X), the json
+ decoder incorrectly decoded surrogate pairs.
+
+* some FreeBSD fixes.
+
+Note that CFFI 0.8.1 was released. Both versions 0.8 and 0.8.1 are
+compatible with both PyPy 2.2 and 2.2.1.
+
+
+Cheers,
+Armin Rigo & everybody
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
@@ -15,3 +15,29 @@
.. branch: armhf-singlefloat
JIT support for singlefloats on ARM using the hardfloat ABI
+
+.. branch: voidtype_strformat
+Better support for record numpy arrays
+
+.. branch: osx-eci-frameworks-makefile
+OSX: Ensure frameworks end up in Makefile when specified in External compilation info
+
+.. branch: less-stringly-ops
+Use subclasses of SpaceOperation instead of SpaceOperator objects.
+Random cleanups in flowspace and annotator.
+
+.. branch: ndarray-buffer
+adds support for the buffer= argument to the ndarray ctor
+
+.. branch: better_ftime_detect2
+On OpenBSD do not pull in libcompat.a as it is about to be removed.
+And more generally, if you have gettimeofday(2) you will not need ftime(3).
+
+.. branch: timeb_h
+Remove dependency upon <sys/timeb.h> on OpenBSD. This will be disappearing
+along with libcompat.a.
+
+.. branch: OlivierBlanvillain/fix-3-broken-links-on-pypy-published-pap-1386250839215
+Fix 3 broken links on PyPy published papers in docs.
+
+.. branch: jit-ordereddict
diff --git a/pypy/interpreter/buffer.py b/pypy/interpreter/buffer.py
--- a/pypy/interpreter/buffer.py
+++ b/pypy/interpreter/buffer.py
@@ -47,6 +47,9 @@
def get_raw_address(self):
raise ValueError("no raw buffer")
+ def is_writable(self):
+ return False
+
# __________ app-level support __________
def descr_len(self, space):
@@ -135,6 +138,9 @@
__slots__ = () # no extra slot here
+ def is_writable(self):
+ return True
+
def setitem(self, index, char):
"Write a character into the buffer."
raise NotImplementedError # Must be overriden. No bounds checks.
diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py
--- a/pypy/interpreter/gateway.py
+++ b/pypy/interpreter/gateway.py
@@ -806,8 +806,8 @@
raise TypeError("Varargs and keywords not supported in unwrap_spec")
argspec = ', '.join([arg for arg in args.args[1:]])
func_code = py.code.Source("""
- def f(w_obj, %(args)s):
- return w_obj.%(func_name)s(%(args)s)
+ def f(self, %(args)s):
+ return self.%(func_name)s(%(args)s)
""" % {'args': argspec, 'func_name': func.func_name})
d = {}
exec func_code.compile() in d
@@ -822,7 +822,7 @@
else:
assert isinstance(unwrap_spec, dict)
unwrap_spec = unwrap_spec.copy()
- unwrap_spec['w_obj'] = base_cls
+ unwrap_spec['self'] = base_cls
return interp2app(globals()['unwrap_spec'](**unwrap_spec)(f))
class interp2app(W_Root):
diff --git a/pypy/module/__builtin__/app_operation.py b/pypy/module/__builtin__/app_operation.py
--- a/pypy/module/__builtin__/app_operation.py
+++ b/pypy/module/__builtin__/app_operation.py
@@ -1,4 +1,5 @@
+import operator
+
def bin(x):
- if not isinstance(x, (int, long)):
- raise TypeError("must be int or long")
- return x.__format__("#b")
+ value = operator.index(x)
+ return value.__format__("#b")
diff --git a/pypy/module/__builtin__/test/test_builtin.py b/pypy/module/__builtin__/test/test_builtin.py
--- a/pypy/module/__builtin__/test/test_builtin.py
+++ b/pypy/module/__builtin__/test/test_builtin.py
@@ -46,6 +46,15 @@
assert bin(2L) == "0b10"
assert bin(-2L) == "-0b10"
raises(TypeError, bin, 0.)
+ class C(object):
+ def __index__(self):
+ return 42
+ assert bin(C()) == bin(42)
+ class D(object):
+ def __int__(self):
+ return 42
+ exc = raises(TypeError, bin, D())
+ assert "index" in exc.value.message
def test_unichr(self):
import sys
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
@@ -5,7 +5,9 @@
from pypy.interpreter.typedef import TypeDef, make_weakref_descr
from pypy.module._cffi_backend import cdataobj, ctypeptr, ctypearray
+from rpython.rtyper.annlowlevel import llstr
from rpython.rtyper.lltypesystem import rffi
+from rpython.rtyper.lltypesystem.rstr import copy_string_to_raw
class LLBuffer(RWBuffer):
@@ -34,8 +36,7 @@
def setslice(self, start, string):
raw_cdata = rffi.ptradd(self.raw_cdata, start)
- for i in range(len(string)):
- raw_cdata[i] = string[i]
+ copy_string_to_raw(llstr(string), raw_cdata, 0, len(string))
class MiniBuffer(W_Root):
@@ -59,6 +60,9 @@
def descr__buffer__(self, space):
return self.buffer.descr__buffer__(space)
+ def descr_str(self, space):
+ return space.wrap(self.buffer.as_str())
+
MiniBuffer.typedef = TypeDef(
"buffer",
@@ -68,6 +72,7 @@
__setitem__ = interp2app(MiniBuffer.descr_setitem),
__buffer__ = interp2app(MiniBuffer.descr__buffer__),
__weakref__ = make_weakref_descr(MiniBuffer),
+ __str__ = interp2app(MiniBuffer.descr_str),
)
MiniBuffer.typedef.acceptable_as_base_class = False
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
@@ -5,7 +5,7 @@
from pypy.interpreter.gateway import interp2app
from pypy.interpreter.typedef import TypeDef, make_weakref_descr
-from rpython.rlib import objectmodel, rgc
+from rpython.rlib import rgc
from rpython.rlib.objectmodel import keepalive_until_here, specialize
from rpython.rtyper.lltypesystem import lltype, rffi
from rpython.tool.sourcetools import func_with_new_name
@@ -206,8 +206,7 @@
w_value.get_array_length() == length):
# fast path: copying from exactly the correct type
s = w_value._cdata
- for i in range(ctitemsize * length):
- cdata[i] = s[i]
+ rffi.c_memcpy(cdata, s, ctitemsize * length)
keepalive_until_here(w_value)
return
#
@@ -259,7 +258,6 @@
space = self.space
if isinstance(w_other, W_CData):
from pypy.module._cffi_backend import ctypeptr, ctypearray
- from pypy.module._cffi_backend import ctypevoid
ct = w_other.ctype
if isinstance(ct, ctypearray.W_CTypeArray):
ct = ct.ctptr
@@ -424,6 +422,12 @@
def get_array_length(self):
return self.length
+ def _sizeof(self):
+ from pypy.module._cffi_backend.ctypeptr import W_CTypePtrOrArray
+ ctype = self.ctype
+ assert isinstance(ctype, W_CTypePtrOrArray)
+ return self.length * ctype.ctitem.size
+
class W_CDataHandle(W_CData):
_attrs_ = ['w_keepalive']
diff --git a/pypy/module/_cffi_backend/handle.py b/pypy/module/_cffi_backend/handle.py
--- a/pypy/module/_cffi_backend/handle.py
+++ b/pypy/module/_cffi_backend/handle.py
@@ -42,7 +42,7 @@
if self.handles[d]() is None:
self.look_distance = d + 1
return d
- # full! extend, but don't use '!=' here
+ # full! extend, but don't use '+=' here
self.handles = self.handles + [dead_ref] * (length // 3 + 5)
self.look_distance = length + 1
return length
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
@@ -2143,7 +2143,13 @@
c = newp(BCharArray, b"hi there")
#
buf = buffer(c)
- assert str(buf).startswith('<_cffi_backend.buffer object at 0x')
+ assert repr(buf).startswith('<_cffi_backend.buffer object at 0x')
+ assert bytes(buf) == b"hi there\x00"
+ if sys.version_info < (3,):
+ assert str(buf) == "hi there\x00"
+ assert unicode(buf) == u+"hi there\x00"
+ else:
+ assert str(buf) == repr(buf)
# --mb_length--
assert len(buf) == len(b"hi there\x00")
# --mb_item--
@@ -3125,6 +3131,12 @@
py.test.raises(TypeError, "p + cast(new_primitive_type('int'), 42)")
py.test.raises(TypeError, "p - cast(new_primitive_type('int'), 42)")
+def test_sizeof_sliced_array():
+ BInt = new_primitive_type("int")
+ BArray = new_array_type(new_pointer_type(BInt), 10)
+ p = newp(BArray, None)
+ assert sizeof(p[2:9]) == 7 * sizeof(BInt)
+
def test_version():
# this test is here mostly for PyPy
diff --git a/pypy/module/_rawffi/array.py b/pypy/module/_rawffi/array.py
--- a/pypy/module/_rawffi/array.py
+++ b/pypy/module/_rawffi/array.py
@@ -15,6 +15,7 @@
from pypy.module._rawffi.interp_rawffi import unpack_shape_with_length
from pypy.module._rawffi.interp_rawffi import read_ptr, write_ptr
from rpython.rlib.rarithmetic import r_uint
+from rpython.rlib import rgc
class W_Array(W_DataShape):
@@ -220,6 +221,7 @@
def __init__(self, space, shape, length):
W_ArrayInstance.__init__(self, space, shape, length, 0)
+ @rgc.must_be_light_finalizer
def __del__(self):
if self.ll_buffer:
self._free()
diff --git a/pypy/module/_rawffi/structure.py b/pypy/module/_rawffi/structure.py
--- a/pypy/module/_rawffi/structure.py
+++ b/pypy/module/_rawffi/structure.py
@@ -16,7 +16,7 @@
from pypy.module._rawffi.interp_rawffi import unroll_letters_for_numbers
from pypy.module._rawffi.interp_rawffi import size_alignment
from pypy.module._rawffi.interp_rawffi import read_ptr, write_ptr
-from rpython.rlib import clibffi
+from rpython.rlib import clibffi, rgc
from rpython.rlib.rarithmetic import intmask, signedtype, widen
from rpython.rlib.rarithmetic import r_uint, r_ulonglong, r_longlong
@@ -226,6 +226,7 @@
fieldtypes)
return self.ffi_struct.ffistruct
+ @rgc.must_be_light_finalizer
def __del__(self):
if self.ffi_struct:
lltype.free(self.ffi_struct, flavor='raw')
@@ -380,6 +381,7 @@
def __init__(self, space, shape):
W_StructureInstance.__init__(self, space, shape, 0)
+ @rgc.must_be_light_finalizer
def __del__(self):
if self.ll_buffer:
self._free()
diff --git a/pypy/module/_rawffi/test/test_tracker.py b/pypy/module/_rawffi/test/test_tracker.py
--- a/pypy/module/_rawffi/test/test_tracker.py
+++ b/pypy/module/_rawffi/test/test_tracker.py
@@ -1,9 +1,21 @@
+import py
+from pypy.conftest import option
from pypy.module._rawffi.tracker import Tracker
+
class AppTestTracker:
spaceconfig = dict(usemodules=['_rawffi', 'struct'])
def setup_class(cls):
+ #
+ # detect if we're running on PyPy with DO_TRACING not compiled in
+ if option.runappdirect:
+ try:
+ import _rawffi
+ _rawffi._num_of_allocated_objects()
+ except (ImportError, RuntimeError), e:
+ py.test.skip(str(e))
+ #
Tracker.DO_TRACING = True
def test_array(self):
diff --git a/pypy/module/_rawffi/tracker.py b/pypy/module/_rawffi/tracker.py
--- a/pypy/module/_rawffi/tracker.py
+++ b/pypy/module/_rawffi/tracker.py
@@ -2,9 +2,11 @@
""" The file that keeps track about freed/kept-alive objects allocated
by _rawffi. Used for debugging ctypes
"""
+from pypy.interpreter.error import OperationError
+
class Tracker(object):
- DO_TRACING = True
+ DO_TRACING = False # make sure this stays False by default!
def __init__(self):
self.alloced = {}
@@ -20,6 +22,9 @@
tracker = Tracker()
def num_of_allocated_objects(space):
+ if not tracker.DO_TRACING:
+ raise OperationError(space.w_RuntimeError,
+ space.wrap("DO_TRACING not enabled in this PyPy"))
return space.wrap(len(tracker.alloced))
def print_alloced_objects(space):
diff --git a/pypy/module/_sre/interp_sre.py b/pypy/module/_sre/interp_sre.py
--- a/pypy/module/_sre/interp_sre.py
+++ b/pypy/module/_sre/interp_sre.py
@@ -415,7 +415,13 @@
except OperationError, e:
if not e.match(space, space.w_TypeError):
raise
- w_groupnum = space.getitem(self.srepat.w_groupindex, w_arg)
+ try:
+ w_groupnum = space.getitem(self.srepat.w_groupindex, w_arg)
+ except OperationError, e:
+ if not e.match(space, space.w_KeyError):
+ raise
+ raise OperationError(space.w_IndexError,
+ space.wrap("no such group"))
groupnum = space.int_w(w_groupnum)
if groupnum == 0:
return self.ctx.match_start, self.ctx.match_end
diff --git a/pypy/module/_sre/test/test_app_sre.py b/pypy/module/_sre/test/test_app_sre.py
--- a/pypy/module/_sre/test/test_app_sre.py
+++ b/pypy/module/_sre/test/test_app_sre.py
@@ -172,6 +172,9 @@
assert ("1", "1", None) == m.group(1, 2, 3)
assert ("1", None) == m.group("first", "second")
raises(IndexError, m.group, 1, 4)
+ assert ("1", None) == m.group(1, "second")
+ raises(IndexError, m.group, 'foobarbaz')
+ raises(IndexError, m.group, 'first', 'foobarbaz')
def test_expand(self):
import re
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
@@ -711,8 +711,12 @@
raise ssl_error(space, "SSL_CTX_use_certificate_chain_file error")
# ssl compatibility
- libssl_SSL_CTX_set_options(ss.ctx,
- SSL_OP_ALL & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS)
+ options = SSL_OP_ALL & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
+ if protocol != PY_SSL_VERSION_SSL2:
+ # SSLv2 is extremely broken, don't use it unless a user specifically
+ # requests it
+ options |= SSL_OP_NO_SSLv2
+ libssl_SSL_CTX_set_options(ss.ctx, options)
verification_mode = SSL_VERIFY_NONE
if cert_mode == PY_SSL_CERT_OPTIONAL:
@@ -724,7 +728,7 @@
libssl_SSL_set_fd(ss.ssl, sock_fd) # set the socket for SSL
# The ACCEPT_MOVING_WRITE_BUFFER flag is necessary because the address
# of a str object may be changed by the garbage collector.
- libssl_SSL_set_mode(ss.ssl,
+ libssl_SSL_set_mode(ss.ssl,
SSL_MODE_AUTO_RETRY | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER)
# If the socket is in non-blocking mode or timeout mode, set the BIO
diff --git a/pypy/module/_weakref/interp__weakref.py b/pypy/module/_weakref/interp__weakref.py
--- a/pypy/module/_weakref/interp__weakref.py
+++ b/pypy/module/_weakref/interp__weakref.py
@@ -52,6 +52,7 @@
# weakref callbacks are not invoked eagerly here. They are
# invoked by self.__del__() anyway.
+ @jit.dont_look_inside
def get_or_make_weakref(self, w_subtype, w_obj):
space = self.space
w_weakreftype = space.gettypeobject(W_Weakref.typedef)
@@ -70,6 +71,7 @@
self.append_wref_to(w_ref)
return w_ref
+ @jit.dont_look_inside
def get_or_make_proxy(self, w_obj):
space = self.space
if self.cached_proxy is not None:
@@ -122,6 +124,7 @@
W_WeakrefBase.activate_callback,
'weakref callback of ')
+ @jit.dont_look_inside
def make_weakref_with_callback(self, w_subtype, w_obj, w_callable):
space = self.space
w_ref = space.allocate_instance(W_Weakref, w_subtype)
@@ -129,6 +132,7 @@
self.append_wref_to(w_ref)
return w_ref
+ @jit.dont_look_inside
def make_proxy_with_callback(self, w_obj, w_callable):
space = self.space
if space.is_true(space.callable(w_obj)):
@@ -239,15 +243,16 @@
w_obj.setweakref(space, lifeline)
return lifeline
- at jit.dont_look_inside
+
def get_or_make_weakref(space, w_subtype, w_obj):
return getlifeline(space, w_obj).get_or_make_weakref(w_subtype, w_obj)
- at jit.dont_look_inside
+
def make_weakref_with_callback(space, w_subtype, w_obj, w_callable):
lifeline = getlifelinewithcallbacks(space, w_obj)
return lifeline.make_weakref_with_callback(w_subtype, w_obj, w_callable)
+
def descr__new__weakref(space, w_subtype, w_obj, w_callable=None,
__args__=None):
if __args__.arguments_w:
@@ -312,15 +317,16 @@
w_obj = force(space, self)
return space.call_args(w_obj, __args__)
- at jit.dont_look_inside
+
def get_or_make_proxy(space, w_obj):
return getlifeline(space, w_obj).get_or_make_proxy(w_obj)
- at jit.dont_look_inside
+
def make_proxy_with_callback(space, w_obj, w_callable):
lifeline = getlifelinewithcallbacks(space, w_obj)
return lifeline.make_proxy_with_callback(w_obj, w_callable)
+
def proxy(space, w_obj, w_callable=None):
"""Create a proxy object that weakly references 'obj'.
'callback', if given, is called with the proxy as an argument when 'obj'
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
@@ -26,6 +26,7 @@
from pypy.module.__builtin__.descriptor import W_Property
from pypy.module.__builtin__.interp_classobj import W_ClassObject
from pypy.module.__builtin__.interp_memoryview import W_MemoryView
+from pypy.module.micronumpy.base import W_NDimArray
from rpython.rlib.entrypoint import entrypoint_lowlevel
from rpython.rlib.rposix import is_valid_fd, validate_fd
from rpython.rlib.unroll import unrolling_iterable
@@ -399,16 +400,16 @@
'_PyObject_CallFunction_SizeT', '_PyObject_CallMethod_SizeT',
'PyBuffer_FromMemory', 'PyBuffer_FromReadWriteMemory', 'PyBuffer_FromObject',
- 'PyBuffer_FromReadWriteObject', 'PyBuffer_New', 'PyBuffer_Type', 'init_bufferobject',
+ 'PyBuffer_FromReadWriteObject', 'PyBuffer_New', 'PyBuffer_Type', '_Py_init_bufferobject',
'PyCObject_FromVoidPtr', 'PyCObject_FromVoidPtrAndDesc', 'PyCObject_AsVoidPtr',
'PyCObject_GetDesc', 'PyCObject_Import', 'PyCObject_SetVoidPtr',
- 'PyCObject_Type', 'init_pycobject',
+ 'PyCObject_Type', '_Py_init_pycobject',
'PyCapsule_New', 'PyCapsule_IsValid', 'PyCapsule_GetPointer',
'PyCapsule_GetName', 'PyCapsule_GetDestructor', 'PyCapsule_GetContext',
'PyCapsule_SetPointer', 'PyCapsule_SetName', 'PyCapsule_SetDestructor',
- 'PyCapsule_SetContext', 'PyCapsule_Import', 'PyCapsule_Type', 'init_capsule',
+ 'PyCapsule_SetContext', 'PyCapsule_Import', 'PyCapsule_Type', '_Py_init_capsule',
'PyObject_AsReadBuffer', 'PyObject_AsWriteBuffer', 'PyObject_CheckReadBuffer',
@@ -469,6 +470,7 @@
"Complex": "space.w_complex",
"ByteArray": "space.w_bytearray",
"MemoryView": "space.gettypeobject(W_MemoryView.typedef)",
+ "Array": "space.gettypeobject(W_NDimArray.typedef)",
"BaseObject": "space.w_object",
'None': 'space.type(space.w_None)',
'NotImplemented': 'space.type(space.w_NotImplemented)',
@@ -685,11 +687,15 @@
globals()['va_get_%s' % name_no_star] = func
def setup_init_functions(eci, translating):
- init_buffer = rffi.llexternal('init_bufferobject', [], lltype.Void,
+ if translating:
+ prefix = 'PyPy'
+ else:
+ prefix = 'cpyexttest'
+ init_buffer = rffi.llexternal('_%s_init_bufferobject' % prefix, [], lltype.Void,
compilation_info=eci, _nowrapper=True)
- init_pycobject = rffi.llexternal('init_pycobject', [], lltype.Void,
+ init_pycobject = rffi.llexternal('_%s_init_pycobject' % prefix, [], lltype.Void,
compilation_info=eci, _nowrapper=True)
- init_capsule = rffi.llexternal('init_capsule', [], lltype.Void,
+ init_capsule = rffi.llexternal('_%s_init_capsule' % prefix, [], lltype.Void,
compilation_info=eci, _nowrapper=True)
INIT_FUNCTIONS.extend([
lambda space: init_buffer(),
@@ -697,12 +703,8 @@
lambda space: init_capsule(),
])
from pypy.module.posix.interp_posix import add_fork_hook
- if translating:
- reinit_tls = rffi.llexternal('PyThread_ReInitTLS', [], lltype.Void,
- compilation_info=eci)
- else:
- reinit_tls = rffi.llexternal('PyPyThread_ReInitTLS', [], lltype.Void,
- compilation_info=eci)
+ reinit_tls = rffi.llexternal('%sThread_ReInitTLS' % prefix, [], lltype.Void,
+ compilation_info=eci)
add_fork_hook('child', reinit_tls)
def init_function(func):
@@ -744,7 +746,7 @@
from rpython.translator.c.database import LowLevelDatabase
db = LowLevelDatabase()
- generate_macros(export_symbols, rename=True, do_deref=True)
+ generate_macros(export_symbols, prefix='cpyexttest')
# Structure declaration code
members = []
@@ -810,7 +812,7 @@
INTERPLEVEL_API[name] = w_obj
- name = name.replace('Py', 'PyPy')
+ name = name.replace('Py', 'cpyexttest')
if isptr:
ptr = ctypes.c_void_p.in_dll(bridge, name)
if typ == 'PyObject*':
@@ -822,7 +824,7 @@
ptr.value = ctypes.cast(ll2ctypes.lltype2ctypes(value),
ctypes.c_void_p).value
elif typ in ('PyObject*', 'PyTypeObject*'):
- if name.startswith('PyPyExc_'):
+ if name.startswith('PyPyExc_') or name.startswith('cpyexttestExc_'):
# we already have the pointer
in_dll = ll2ctypes.get_ctypes_type(PyObject).in_dll(bridge, name)
py_obj = ll2ctypes.ctypes2lltype(PyObject, in_dll)
@@ -857,28 +859,27 @@
setup_init_functions(eci, translating=False)
return modulename.new(ext='')
-def generate_macros(export_symbols, rename=True, do_deref=True):
+def mangle_name(prefix, name):
+ if name.startswith('Py'):
+ return prefix + name[2:]
+ elif name.startswith('_Py'):
+ return '_' + prefix + name[3:]
+ else:
+ return None
+
+def generate_macros(export_symbols, prefix):
"NOT_RPYTHON"
pypy_macros = []
renamed_symbols = []
for name in export_symbols:
- if name.startswith("PyPy"):
- renamed_symbols.append(name)
- continue
- if not rename:
- continue
name = name.replace("#", "")
- newname = name.replace('Py', 'PyPy')
- if not rename:
- newname = name
+ newname = mangle_name(prefix, name)
+ assert newname, name
pypy_macros.append('#define %s %s' % (name, newname))
if name.startswith("PyExc_"):
pypy_macros.append('#define _%s _%s' % (name, newname))
renamed_symbols.append(newname)
- if rename:
- export_symbols[:] = renamed_symbols
- else:
- export_symbols[:] = [sym.replace("#", "") for sym in export_symbols]
+ export_symbols[:] = renamed_symbols
# Generate defines
for macro_name, size in [
@@ -1039,7 +1040,7 @@
from rpython.translator.c.database import LowLevelDatabase
db = LowLevelDatabase()
- generate_macros(export_symbols, rename=False, do_deref=False)
+ generate_macros(export_symbols, prefix='PyPy')
functions = generate_decls_and_callbacks(db, [], api_struct=False)
code = "#include <Python.h>\n" + "\n".join(functions)
@@ -1069,7 +1070,8 @@
export_struct(name, struct)
for name, func in FUNCTIONS.iteritems():
- deco = entrypoint_lowlevel("cpyext", func.argtypes, name, relax=True)
+ newname = mangle_name('PyPy', name) or name
+ deco = entrypoint_lowlevel("cpyext", func.argtypes, newname, relax=True)
deco(func.get_wrapper(space))
setup_init_functions(eci, translating=True)
diff --git a/pypy/module/cpyext/include/bufferobject.h b/pypy/module/cpyext/include/bufferobject.h
--- a/pypy/module/cpyext/include/bufferobject.h
+++ b/pypy/module/cpyext/include/bufferobject.h
@@ -37,7 +37,7 @@
PyObject* PyBuffer_New(Py_ssize_t size);
-void init_bufferobject(void);
+void _Py_init_bufferobject(void);
#ifdef __cplusplus
}
diff --git a/pypy/module/cpyext/include/pycapsule.h b/pypy/module/cpyext/include/pycapsule.h
--- a/pypy/module/cpyext/include/pycapsule.h
+++ b/pypy/module/cpyext/include/pycapsule.h
@@ -50,7 +50,7 @@
PyAPI_FUNC(void *) PyCapsule_Import(const char *name, int no_block);
-void init_capsule(void);
+void _Py_init_capsule(void);
#ifdef __cplusplus
}
diff --git a/pypy/module/cpyext/include/pycobject.h b/pypy/module/cpyext/include/pycobject.h
--- a/pypy/module/cpyext/include/pycobject.h
+++ b/pypy/module/cpyext/include/pycobject.h
@@ -48,7 +48,7 @@
} PyCObject;
#endif
-void init_pycobject(void);
+void _Py_init_pycobject(void);
#ifdef __cplusplus
}
diff --git a/pypy/module/cpyext/include/pyconfig.h b/pypy/module/cpyext/include/pyconfig.h
--- a/pypy/module/cpyext/include/pyconfig.h
+++ b/pypy/module/cpyext/include/pyconfig.h
@@ -25,6 +25,22 @@
#define Py_UNICODE_SIZE 2
#endif
+#ifndef Py_BUILD_CORE /* not building the core - must be an ext */
+# if defined(_MSC_VER)
+ /* So MSVC users need not specify the .lib file in
+ * their Makefile (other compilers are generally
+ * taken care of by distutils.) */
+# ifdef _DEBUG
+# error("debug first with cpython")
+# pragma comment(lib,"python27.lib")
+# else
+# pragma comment(lib,"python27.lib")
+# endif /* _DEBUG */
+# endif
+#endif /* _MSC_VER */
+
+
+
#ifdef __cplusplus
}
#endif
diff --git a/pypy/module/cpyext/src/bufferobject.c b/pypy/module/cpyext/src/bufferobject.c
--- a/pypy/module/cpyext/src/bufferobject.c
+++ b/pypy/module/cpyext/src/bufferobject.c
@@ -783,7 +783,7 @@
return size;
}
-void init_bufferobject(void)
+void _Py_init_bufferobject(void)
{
PyType_Ready(&PyBuffer_Type);
}
diff --git a/pypy/module/cpyext/src/capsule.c b/pypy/module/cpyext/src/capsule.c
--- a/pypy/module/cpyext/src/capsule.c
+++ b/pypy/module/cpyext/src/capsule.c
@@ -321,7 +321,7 @@
PyCapsule_Type__doc__ /*tp_doc*/
};
-void init_capsule()
+void _Py_init_capsule()
{
PyType_Ready(&PyCapsule_Type);
}
diff --git a/pypy/module/cpyext/src/cobject.c b/pypy/module/cpyext/src/cobject.c
--- a/pypy/module/cpyext/src/cobject.c
+++ b/pypy/module/cpyext/src/cobject.c
@@ -156,7 +156,7 @@
PyCObject_Type__doc__ /*tp_doc*/
};
-void init_pycobject()
+void _Py_init_pycobject()
{
PyType_Ready(&PyCObject_Type);
}
diff --git a/pypy/module/cpyext/src/ndarrayobject.c b/pypy/module/cpyext/src/ndarrayobject.c
--- a/pypy/module/cpyext/src/ndarrayobject.c
+++ b/pypy/module/cpyext/src/ndarrayobject.c
@@ -3,8 +3,6 @@
#include "numpy/arrayobject.h"
#include <string.h> /* memset, memcpy */
-PyTypeObject PyArray_Type;
-
void
_PyArray_FILLWBYTE(PyObject* obj, int val) {
memset(PyArray_DATA(obj), val, PyArray_NBYTES(obj));
diff --git a/pypy/module/cpyext/test/test_ndarrayobject.py b/pypy/module/cpyext/test/test_ndarrayobject.py
--- a/pypy/module/cpyext/test/test_ndarrayobject.py
+++ b/pypy/module/cpyext/test/test_ndarrayobject.py
@@ -286,3 +286,19 @@
assert dt.num == 11
+ def test_pass_ndarray_object_to_c(self):
+ from _numpypy.multiarray import ndarray
+ mod = self.import_extension('foo', [
+ ("check_array", "METH_VARARGS",
+ '''
+ PyObject* obj;
+ if (!PyArg_ParseTuple(args, "O!", &PyArray_Type, &obj))
+ return NULL;
+ Py_INCREF(obj);
+ return obj;
+ '''),
+ ], prologue='#include <numpy/arrayobject.h>')
+ array = ndarray((3, 4), dtype='d')
+ assert mod.check_array(array) is array
+ raises(TypeError, "mod.check_array(42)")
+
diff --git a/pypy/module/cpyext/test/test_thread.py b/pypy/module/cpyext/test/test_thread.py
--- a/pypy/module/cpyext/test/test_thread.py
+++ b/pypy/module/cpyext/test/test_thread.py
@@ -8,8 +8,10 @@
module = self.import_extension('foo', [
("get_thread_ident", "METH_NOARGS",
"""
- /* Use the 'PyPy' prefix to ensure we access our functions */
- return PyInt_FromLong(PyPyThread_get_thread_ident());
+#ifndef PyThread_get_thread_ident
+#error "seems we are not accessing PyPy's functions"
+#endif
+ return PyInt_FromLong(PyThread_get_thread_ident());
"""),
])
import thread, threading
@@ -32,17 +34,19 @@
module = self.import_extension('foo', [
("test_acquire_lock", "METH_NOARGS",
"""
- /* Use the 'PyPy' prefix to ensure we access our functions */
- PyThread_type_lock lock = PyPyThread_allocate_lock();
- if (PyPyThread_acquire_lock(lock, 1) != 1) {
+#ifndef PyThread_allocate_lock
+#error "seems we are not accessing PyPy's functions"
+#endif
+ PyThread_type_lock lock = PyThread_allocate_lock();
+ if (PyThread_acquire_lock(lock, 1) != 1) {
PyErr_SetString(PyExc_AssertionError, "first acquire");
return NULL;
}
- if (PyPyThread_acquire_lock(lock, 0) != 0) {
+ if (PyThread_acquire_lock(lock, 0) != 0) {
PyErr_SetString(PyExc_AssertionError, "second acquire");
return NULL;
}
- PyPyThread_free_lock(lock);
+ PyThread_free_lock(lock);
Py_RETURN_NONE;
"""),
@@ -53,15 +57,17 @@
module = self.import_extension('foo', [
("test_release_lock", "METH_NOARGS",
"""
- /* Use the 'PyPy' prefix to ensure we access our functions */
- PyThread_type_lock lock = PyPyThread_allocate_lock();
- PyPyThread_acquire_lock(lock, 1);
- PyPyThread_release_lock(lock);
- if (PyPyThread_acquire_lock(lock, 0) != 1) {
+#ifndef PyThread_release_lock
+#error "seems we are not accessing PyPy's functions"
+#endif
+ PyThread_type_lock lock = PyThread_allocate_lock();
+ PyThread_acquire_lock(lock, 1);
+ PyThread_release_lock(lock);
+ if (PyThread_acquire_lock(lock, 0) != 1) {
PyErr_SetString(PyExc_AssertionError, "first acquire");
return NULL;
}
- PyPyThread_free_lock(lock);
+ PyThread_free_lock(lock);
Py_RETURN_NONE;
"""),
diff --git a/pypy/module/itertools/interp_itertools.py b/pypy/module/itertools/interp_itertools.py
--- a/pypy/module/itertools/interp_itertools.py
+++ b/pypy/module/itertools/interp_itertools.py
@@ -342,10 +342,8 @@
if space.is_w(w_startstop, space.w_None):
start = 0
else:
- start = space.int_w(w_startstop)
- if start < 0:
- raise OperationError(space.w_ValueError, space.wrap(
- "Indicies for islice() must be non-negative integers."))
+ start = self.arg_int_w(w_startstop, 0,
+ "Indicies for islice() must be None or non-negative integers")
w_stop = args_w[0]
else:
raise OperationError(space.w_TypeError, space.wrap("islice() takes at most 4 arguments (" + str(num_args) + " given)"))
@@ -353,10 +351,8 @@
if space.is_w(w_stop, space.w_None):
stop = -1
else:
- stop = space.int_w(w_stop)
- if stop < 0:
- raise OperationError(space.w_ValueError, space.wrap(
- "Stop argument must be a non-negative integer or None."))
+ stop = self.arg_int_w(w_stop, 0,
+ "Stop argument must be a non-negative integer or None.")
stop = max(start, stop) # for obscure CPython compatibility
if num_args == 2:
@@ -364,10 +360,8 @@
if space.is_w(w_step, space.w_None):
step = 1
else:
- step = space.int_w(w_step)
- if step < 1:
- raise OperationError(space.w_ValueError, space.wrap(
- "Step must be one or lager for islice()."))
+ step = self.arg_int_w(w_step, 1,
+ "Step for islice() must be a positive integer or None")
else:
step = 1
@@ -375,6 +369,18 @@
self.start = start
self.stop = stop
+ def arg_int_w(self, w_obj, minimum, errormsg):
+ space = self.space
+ try:
+ result = space.int_w(w_obj)
+ except OperationError, e:
+ if e.async(space):
+ raise
+ result = -1
+ if result < minimum:
+ raise OperationError(space.w_ValueError, space.wrap(errormsg))
+ return result
+
def iter_w(self):
return self.space.wrap(self)
diff --git a/pypy/module/itertools/test/test_itertools.py b/pypy/module/itertools/test/test_itertools.py
--- a/pypy/module/itertools/test/test_itertools.py
+++ b/pypy/module/itertools/test/test_itertools.py
@@ -304,6 +304,11 @@
raises(TypeError, itertools.islice, [], 0, 0, 0, 0)
+ # why not TypeError? Because CPython
+ raises(ValueError, itertools.islice, [], "a", 1, 2)
+ raises(ValueError, itertools.islice, [], 0, "a", 2)
+ raises(ValueError, itertools.islice, [], 0, 1, "a")
+
def test_chain(self):
import itertools
diff --git a/pypy/module/math/app_math.py b/pypy/module/math/app_math.py
--- a/pypy/module/math/app_math.py
+++ b/pypy/module/math/app_math.py
@@ -1,13 +1,40 @@
def factorial(x):
- """Find x!."""
+ """factorial(x) -> Integral
+
+ "Find x!. Raise a ValueError if x is negative or non-integral."""
if isinstance(x, float):
fl = int(x)
if fl != x:
raise ValueError("float arguments must be integral")
x = fl
- if x < 0:
- raise ValueError("x must be >= 0")
- res = 1
- for i in range(1, x + 1):
- res *= i
- return res
+
+ if x <= 100:
+ if x < 0:
+ raise ValueError("x must be >= 0")
+ res = 1
+ for i in range(2, x + 1):
+ res *= i
+ return res
+
+ # Experimentally this gap seems good
+ gap = max(100, x >> 7)
+ def _fac_odd(low, high):
+ if low + gap >= high:
+ t = 1
+ for i in range(low, high, 2):
+ t *= i
+ return t
+
+ mid = ((low + high) >> 1) | 1
+ return _fac_odd(low, mid) * _fac_odd(mid, high)
+
+ def _fac1(x):
+ if x <= 2:
+ return 1, 1, x - 1
+ x2 = x >> 1
+ f, g, shift = _fac1(x2)
+ g *= _fac_odd((x2 + 1) | 1, x + 1)
+ return (f * g, g, shift + x2)
+
+ res, _, shift = _fac1(x)
+ return res << shift
diff --git a/pypy/module/math/test/test_factorial.py b/pypy/module/math/test/test_factorial.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/math/test/test_factorial.py
@@ -0,0 +1,29 @@
+import py
+import math
+from pypy.module.math import app_math
+
+def test_factorial_extra():
+ for x in range(1000):
+ r1 = app_math.factorial(x)
+ r2 = math.factorial(x)
+ assert r1 == r2
+ assert type(r1) == type(r2)
+
+def test_timing():
+ py.test.skip("for manual running only")
+ import time
+ x = 5000
+ repeat = 1000
+ r1 = app_math.factorial(x)
+ r2 = math.factorial(x)
+ assert r1 == r2
+ t1 = time.time()
+ for i in range(repeat):
+ app_math.factorial(x)
+ t2 = time.time()
+ for i in range(repeat):
+ math.factorial(x)
+ t3 = time.time()
+ assert r1 == r2
+ print (t2 - t1) / repeat
+ print (t3 - t2) / repeat
diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py
--- a/pypy/module/micronumpy/__init__.py
+++ b/pypy/module/micronumpy/__init__.py
@@ -10,7 +10,7 @@
'array': 'interp_numarray.array',
'zeros': 'interp_numarray.zeros',
'empty': 'interp_numarray.zeros',
- 'ones': 'interp_numarray.ones',
+ 'empty_like': 'interp_numarray.empty_like',
'_reconstruct' : 'interp_numarray._reconstruct',
'scalar' : 'interp_numarray.build_scalar',
'dot': 'interp_arrayops.dot',
@@ -106,8 +106,6 @@
('logaddexp2', 'logaddexp2'),
('real', 'real'),
('imag', 'imag'),
- ('ones_like', 'ones_like'),
- ('zeros_like', 'zeros_like'),
]:
interpleveldefs[exposed] = "interp_ufuncs.get(space).%s" % impl
diff --git a/pypy/module/micronumpy/app_numpy.py b/pypy/module/micronumpy/app_numpy.py
--- a/pypy/module/micronumpy/app_numpy.py
+++ b/pypy/module/micronumpy/app_numpy.py
@@ -12,7 +12,9 @@
if dtype is None:
test = _numpypy.multiarray.array([start, stop, step, 0])
dtype = test.dtype
- arr = _numpypy.multiarray.zeros(int(math.ceil((stop - start) / step)), dtype=dtype)
+ length = math.ceil((float(stop) - start) / step)
+ length = int(length)
+ arr = _numpypy.multiarray.zeros(length, dtype=dtype)
i = start
for j in range(arr.size):
arr[j] = i
diff --git a/pypy/module/micronumpy/arrayimpl/concrete.py b/pypy/module/micronumpy/arrayimpl/concrete.py
--- a/pypy/module/micronumpy/arrayimpl/concrete.py
+++ b/pypy/module/micronumpy/arrayimpl/concrete.py
@@ -47,7 +47,7 @@
def setslice(self, space, arr):
impl = arr.implementation
if impl.is_scalar():
- self.fill(impl.get_scalar_value())
+ self.fill(space, impl.get_scalar_value())
return
shape = shape_agreement(space, self.get_shape(), arr)
if impl.storage == self.storage:
@@ -100,7 +100,7 @@
tmp = self.get_real(orig_array)
tmp.setslice(space, convert_to_array(space, w_value))
- def get_imag(self, orig_array):
+ def get_imag(self, space, orig_array):
strides = self.get_strides()
backstrides = self.get_backstrides()
if self.dtype.is_complex_type():
@@ -110,11 +110,11 @@
impl = NonWritableArray(self.get_shape(), self.dtype, self.order, strides,
backstrides)
if not self.dtype.is_flexible_type():
- impl.fill(self.dtype.box(0))
+ impl.fill(space, self.dtype.box(0))
return impl
def set_imag(self, space, orig_array, w_value):
- tmp = self.get_imag(orig_array)
+ tmp = self.get_imag(space, orig_array)
tmp.setslice(space, convert_to_array(space, w_value))
# -------------------- applevel get/setitem -----------------------
@@ -357,7 +357,7 @@
self.get_backstrides(),
self.get_shape())
- def fill(self, box):
+ def fill(self, space, box):
self.dtype.itemtype.fill(self.storage, self.dtype.get_size(),
box, 0, self.size, 0)
@@ -392,6 +392,21 @@
def __del__(self):
free_raw_storage(self.storage, track_allocation=False)
+class ConcreteArrayWithBase(ConcreteArrayNotOwning):
+ def __init__(self, shape, dtype, order, strides, backstrides, storage, orig_base):
+ ConcreteArrayNotOwning.__init__(self, shape, dtype, order,
+ strides, backstrides, storage)
+ self.orig_base = orig_base
+
+ def base(self):
+ return self.orig_base
+
+
+class ConcreteNonWritableArrayWithBase(ConcreteArrayWithBase):
+ def descr_setitem(self, space, orig_array, w_index, w_value):
+ raise OperationError(space.w_ValueError, space.wrap(
+ "assignment destination is read-only"))
+
class NonWritableArray(ConcreteArray):
def descr_setitem(self, space, orig_array, w_index, w_value):
@@ -420,8 +435,8 @@
def base(self):
return self.orig_arr
- def fill(self, box):
- loop.fill(self, box.convert_to(self.dtype))
+ def fill(self, space, box):
+ loop.fill(self, box.convert_to(space, self.dtype))
def create_iter(self, shape=None, backward_broadcast=False, require_index=False):
if shape is not None and \
@@ -487,3 +502,6 @@
def getlength(self):
return self.impl.size
+
+ def get_raw_address(self):
+ return self.impl.storage
diff --git a/pypy/module/micronumpy/arrayimpl/scalar.py b/pypy/module/micronumpy/arrayimpl/scalar.py
--- a/pypy/module/micronumpy/arrayimpl/scalar.py
+++ b/pypy/module/micronumpy/arrayimpl/scalar.py
@@ -54,8 +54,7 @@
return self.value
def set_scalar_value(self, w_val):
- assert isinstance(w_val, W_GenericBox)
- self.value = w_val.convert_to(self.dtype)
+ self.value = w_val
def copy(self, space):
scalar = Scalar(self.dtype)
@@ -96,12 +95,12 @@
','.join([str(x) for x in w_arr.get_shape()],))))
if self.dtype.is_complex_type():
self.value = self.dtype.itemtype.composite(
- w_arr.get_scalar_value().convert_to(dtype),
+ w_arr.get_scalar_value().convert_to(space, dtype),
self.value.convert_imag_to(dtype))
else:
self.value = w_arr.get_scalar_value()
- def get_imag(self, orig_array):
+ def get_imag(self, space, orig_array):
if self.dtype.is_complex_type():
scalar = Scalar(self.dtype.float_type)
scalar.value = self.value.convert_imag_to(scalar.dtype)
@@ -125,13 +124,23 @@
','.join([str(x) for x in w_arr.get_shape()],))))
self.value = self.dtype.itemtype.composite(
self.value.convert_real_to(dtype),
- w_arr.get_scalar_value().convert_to(dtype),
+ w_arr.get_scalar_value().convert_to(space, dtype),
)
def descr_getitem(self, space, _, w_idx):
if space.isinstance_w(w_idx, space.w_tuple):
if space.len_w(w_idx) == 0:
return self.get_scalar_value()
+ elif space.isinstance_w(w_idx, space.w_str):
+ if self.dtype.is_record_type():
+ w_val = self.value.descr_getitem(space, w_idx)
+ return convert_to_array(space, w_val)
+ elif space.is_none(w_idx):
+ new_shape = [1]
+ arr = W_NDimArray.from_shape(space, new_shape, self.dtype)
+ arr_iter = arr.create_iter(new_shape)
+ arr_iter.setitem(self.value)
+ return arr
More information about the pypy-commit
mailing list