[pypy-commit] pypy py3.3: merge py3k
pjenvey
noreply at buildbot.pypy.org
Sat Oct 18 00:47:42 CEST 2014
Author: Philip Jenvey <pjenvey at underboss.org>
Branch: py3.3
Changeset: r74008:02cf2f6a3032
Date: 2014-10-17 15:46 -0700
http://bitbucket.org/pypy/pypy/changeset/02cf2f6a3032/
Log: merge py3k
diff too long, truncating to 2000 out of 18832 lines
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -3,8 +3,8 @@
Except when otherwise stated (look for LICENSE files in directories or
information at the beginning of each file) all software and documentation in
-the 'rpython', 'pypy', 'ctype_configure', 'dotviewer', 'demo', and 'lib_pypy'
-directories is licensed as follows:
+the 'rpython', 'pypy', 'ctype_configure', 'dotviewer', 'demo', 'lib_pypy',
+'py', and '_pytest' directories is licensed as follows:
The MIT License
@@ -367,3 +367,43 @@
Detailed license information is contained in the NOTICE file in the
directory.
+
+Licenses and Acknowledgements for Incorporated Software
+=======================================================
+
+This section is an incomplete, but growing list of licenses and
+acknowledgements for third-party software incorporated in the PyPy
+distribution.
+
+License for 'Tcl/Tk'
+--------------------
+
+This copy of PyPy contains library code that may, when used, result in
+the Tcl/Tk library to be loaded. PyPy also includes code that may be
+regarded as being a copy of some parts of the Tcl/Tk header files.
+You may see a copy of the License for Tcl/Tk in the file
+`lib_pypy/_tkinter/license.terms` included here.
+
+License for 'bzip2'
+-------------------
+
+This copy of PyPy may be linked (dynamically or statically) with the
+bzip2 library. You may see a copy of the License for bzip2/libbzip2 at
+
+ http://www.bzip.org/1.0.5/bzip2-manual-1.0.5.html
+
+License for 'openssl'
+---------------------
+
+This copy of PyPy may be linked (dynamically or statically) with the
+openssl library. You may see a copy of the License for OpenSSL at
+
+ https://www.openssl.org/source/license.html
+
+License for '_gdbm'
+------------------
+
+The _gdbm module includes code from gdbm.h, which is distributed under
+the terms of the GPL license version 2 or any later version. Thus the
+_gdbm module, provided in the file lib_pypy/_gdbm.py, is redistributed
+under the terms of the GPL license as well.
diff --git a/lib-python/2.7/test/test_select.py b/lib-python/2.7/test/test_select.py
--- a/lib-python/2.7/test/test_select.py
+++ b/lib-python/2.7/test/test_select.py
@@ -57,7 +57,17 @@
del a[-1]
return sys.__stdout__.fileno()
a[:] = [F()] * 10
- self.assertEqual(select.select([], a, []), ([], a[:5], []))
+ result = select.select([], a, [])
+ # CPython: 'a' ends up with 5 items, because each fileno()
+ # removes an item and at the middle the iteration stops.
+ # PyPy: 'a' ends up empty, because the iteration is done on
+ # a copy of the original list: fileno() is called 10 times.
+ if test_support.check_impl_detail(cpython=True):
+ self.assertEqual(len(result[1]), 5)
+ self.assertEqual(len(a), 5)
+ if test_support.check_impl_detail(pypy=True):
+ self.assertEqual(len(result[1]), 10)
+ self.assertEqual(len(a), 0)
def test_main():
test_support.run_unittest(SelectTestCase)
diff --git a/lib-python/3/test/test_select.py b/lib-python/3/test/test_select.py
--- a/lib-python/3/test/test_select.py
+++ b/lib-python/3/test/test_select.py
@@ -73,7 +73,17 @@
del a[-1]
return sys.__stdout__.fileno()
a[:] = [F()] * 10
- self.assertEqual(select.select([], a, []), ([], a[:5], []))
+ result = select.select([], a, [])
+ # CPython: 'a' ends up with 5 items, because each fileno()
+ # removes an item and at the middle the iteration stops.
+ # PyPy: 'a' ends up empty, because the iteration is done on
+ # a copy of the original list: fileno() is called 10 times.
+ if support.check_impl_detail(cpython=True):
+ self.assertEqual(len(result[1]), 5)
+ self.assertEqual(len(a), 5)
+ if support.check_impl_detail(pypy=True):
+ self.assertEqual(len(result[1]), 10)
+ self.assertEqual(len(a), 0)
def test_main():
support.run_unittest(SelectTestCase)
diff --git a/lib_pypy/_curses.py b/lib_pypy/_curses.py
--- a/lib_pypy/_curses.py
+++ b/lib_pypy/_curses.py
@@ -286,6 +286,13 @@
lib = ffi.verify("""
+#ifdef __APPLE__
+/* the following define is necessary for OS X 10.6+; without it, the
+ Apple-supplied ncurses.h sets NCURSES_OPAQUE to 1, and then Python
+ can't get at the WINDOW flags field. */
+#define NCURSES_OPAQUE 0
+#endif
+
#include <ncurses.h>
#include <panel.h>
#include <term.h>
diff --git a/pypy/doc/how-to-release.rst b/pypy/doc/how-to-release.rst
--- a/pypy/doc/how-to-release.rst
+++ b/pypy/doc/how-to-release.rst
@@ -38,14 +38,16 @@
no JIT: windows, linux, os/x
sandbox: linux, os/x
+* repackage and upload source tar.bz2 to bitbucket and to cobra, as some packagers
+ prefer a clearly labeled source package
* write release announcement pypy/doc/release-x.y(.z).txt
the release announcement should contain a direct link to the download page
* update pypy.org (under extradoc/pypy.org), rebuild and commit
* post announcement on morepypy.blogspot.com
-* send announcements to pypy-dev, python-list,
+* send announcements to twitter.com, pypy-dev, python-list,
python-announce, python-dev ...
* add a tag on the pypy/jitviewer repo that corresponds to pypy release
* add a tag on the codespeed web site that corresponds to pypy release
-
+* revise versioning at https://readthedocs.org/projects/pypy
diff --git a/pypy/doc/release-2.4.0.rst b/pypy/doc/release-2.4.0.rst
--- a/pypy/doc/release-2.4.0.rst
+++ b/pypy/doc/release-2.4.0.rst
@@ -5,7 +5,7 @@
We're pleased to announce PyPy 2.4, which contains significant performance
enhancements and bug fixes.
-You can already download the PyPy 2.4-beta1 pre-release here:
+You can download the PyPy 2.4.0 release here:
http://pypy.org/download.html
@@ -63,6 +63,8 @@
PyPy now uses Python 2.7.8 standard library.
+We fixed a memory leak in IO in the sandbox_ code
+
We welcomed more than 12 new contributors, and conducted two Google
Summer of Code projects, as well as other student projects not
directly related to Summer of Code.
@@ -103,8 +105,9 @@
* Many issues were resolved_ since the 2.3.1 release on June 8
-.. _`whats-new`: http://doc.pypy.org/en/latest/whatsnew-2.3.1.html
+.. _`whats-new`: http://doc.pypy.org/en/latest/whatsnew-2.4.0.html
.. _resolved: https://bitbucket.org/pypy/pypy/issues?status=resolved
+.. _sandbox: http://doc.pypy.org/en/latest/sandbox.html
We have further improvements on the way: rpython file handling,
numpy linalg compatibility, as well
diff --git a/pypy/doc/release-pypy3-2.4.0.rst b/pypy/doc/release-pypy3-2.4.0.rst
new file mode 100644
--- /dev/null
+++ b/pypy/doc/release-pypy3-2.4.0.rst
@@ -0,0 +1,126 @@
+=================================================
+PyPy3 2.4 - Snow White
+=================================================
+
+We're pleased to announce PyPy3 2.4, which contains significant performance
+enhancements and bug fixes.
+
+You can download the PyPy3 2.4.0 release here:
+
+ http://pypy.org/download.html
+
+We would like to thank our donors for the continued support of the PyPy
+project, and for those who donate to our three sub-projects.
+We've shown quite a bit of progress, but we're slowly running out of funds.
+Please consider donating more, or even better convince your employer to donate,
+so we can finish those projects! The three sub-projects are:
+
+* `Py3k`_ (supporting Python 3.x): This is a Python 3.2.5 compatible
+ version we call PyPy3 2.4, and we are working toward a Python 3.3
+ compatible version
+
+* `STM`_ (software transactional memory): We have released a first working version,
+ and continue to try out new promising paths of achieving a fast multithreaded Python
+
+* `NumPy`_ which requires installation of our fork of upstream numpy,
+ available `on bitbucket`_
+
+.. _`Py3k`: http://pypy.org/py3donate.html
+.. _`STM`: http://pypy.org/tmdonate2.html
+.. _`NumPy`: http://pypy.org/numpydonate.html
+.. _`on bitbucket`: https://www.bitbucket.org/pypy/numpy
+
+What is PyPy?
+=============
+
+PyPy is a very compliant Python interpreter, almost a drop-in replacement for
+CPython 2.7 or 3.2.5. It's fast (`pypy 2.4 and cpython 2.7.x`_ performance
+comparison) due to its integrated tracing JIT compiler.
+
+This release supports **x86** machines on most common operating systems
+(Linux 32/64, Mac OS X 64, Windows, and OpenBSD),
+as well as newer **ARM** hardware (ARMv6 or ARMv7, with VFPv3) running Linux.
+
+While we support 32 bit python on Windows, work on the native Windows 64
+bit python is still stalling, we would welcome a volunteer
+to `handle that`_.
+
+.. _`pypy 2.4 and cpython 2.7.x`: http://speed.pypy.org
+.. _`handle that`: http://doc.pypy.org/en/latest/windows.html#what-is-missing-for-a-full-64-bit-translation
+
+PyPy3 Highlights
+================
+
+Issues reported with our previous release were fixed after reports from users on
+our new issue tracker at https://bitbucket.org/pypy/pypy/issues or on IRC at
+#pypy. Here is a summary of the user-facing PyPy3 specific changes:
+
+* Better Windows compatibility, e.g. the nt module functions _getfinalpathname
+ & _getfileinformation are now supported (the former is required for the
+ popular pathlib library for example)
+
+* Various fsencode PEP 383 related fixes to the posix module (readlink, uname,
+ ttyname and ctermid) and improved locale handling
+
+* Switched default binary name os POSIX distributions to 'pypy3' (which
+ symlinks to to 'pypy3.2')
+
+* Fixed a couple different crashes related to parsing Python 3 source code
+
+Further Highlights (shared w/ PyPy2)
+====================================
+
+Benchmarks improved after internal enhancements in string and
+bytearray handling, and a major rewrite of the GIL handling. This means
+that external calls are now a lot faster, especially the CFFI ones. It also
+means better performance in a lot of corner cases with handling strings or
+bytearrays. The main bugfix is handling of many socket objects in your
+program which in the long run used to "leak" memory.
+
+We fixed a memory leak in IO in the sandbox_ code
+
+We welcomed more than 12 new contributors, and conducted two Google
+Summer of Code projects, as well as other student projects not
+directly related to Summer of Code.
+
+* Reduced internal copying of bytearray operations
+
+* Tweak the internal structure of StringBuilder to speed up large string
+ handling, which becomes advantageous on large programs at the cost of slightly
+ slower small *benchmark* type programs.
+
+* Boost performance of thread-local variables in both unjitted and jitted code,
+ this mostly affects errno handling on linux, which makes external calls
+ faster.
+
+* Move to a mixed polling and mutex GIL model that make mutlithreaded jitted
+ code run *much* faster
+
+* Optimize errno handling in linux (x86 and x86-64 only)
+
+* Remove ctypes pythonapi and ctypes.PyDLL, which never worked on PyPy
+
+* Classes in the ast module are now distinct from structures used by
+ the compiler, which simplifies and speeds up translation of our
+ source code to the PyPy binary interpreter
+
+* Win32 now links statically to zlib, expat, bzip, and openssl-1.0.1i.
+ No more missing DLLs
+
+* Many issues were resolved_ since the 2.3.1 release in June
+
+.. _`whats-new`: http://doc.pypy.org/en/latest/whatsnew-2.4.0.html
+.. _resolved: https://bitbucket.org/pypy/pypy/issues?status=resolved
+.. _sandbox: http://doc.pypy.org/en/latest/sandbox.html
+
+We have further improvements on the way: rpython file handling,
+numpy linalg compatibility, as well
+as improved GC and many smaller improvements.
+
+Please try it out and let us know what you think. We especially welcome
+success stories, we know you are using PyPy, please tell us about it!
+
+Cheers
+
+The PyPy Team
+
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
@@ -6,3 +6,19 @@
.. this is a revision shortly after release-2.4.x
.. startrev: 7026746cbb1b
+.. branch: win32-fixes5
+Fix c code generation for msvc so empty "{ }" are avoided in unions,
+Avoid re-opening files created with NamedTemporaryFile,
+Allocate by 4-byte chunks in rffi_platform,
+Skip testing objdump if it does not exist,
+and other small adjustments in own tests
+
+.. branch: rtyper-stuff
+Small internal refactorings in the rtyper.
+
+.. branch: var-in-Some
+Store annotations on the Variable objects, rather than in a big dict.
+Introduce a new framework for double-dispatched annotation implementations.
+
+.. branch: ClassRepr
+Refactor ClassRepr and make normalizecalls independent of the rtyper.
diff --git a/pypy/doc/whatsnew-pypy3-2.4.0.rst b/pypy/doc/whatsnew-pypy3-2.4.0.rst
new file mode 100644
--- /dev/null
+++ b/pypy/doc/whatsnew-pypy3-2.4.0.rst
@@ -0,0 +1,6 @@
+=========================
+What's new in PyPy3 2.4.0
+=========================
+
+.. this is a revision shortly after pypy3-release-2.4.x
+.. startrev: 12b940544622
diff --git a/pypy/doc/windows.rst b/pypy/doc/windows.rst
--- a/pypy/doc/windows.rst
+++ b/pypy/doc/windows.rst
@@ -37,6 +37,13 @@
using a 32 bit Python and vice versa. By default pypy is built using the
Multi-threaded DLL (/MD) runtime environment.
+If you wish to override this detection method to use a different compiler
+(mingw or a different version of MSVC):
+
+* set up the PATH and other environment variables as needed
+* set the `CC` environment variable to compiler exe to be used,
+ for a different version of MSVC `SET CC=cl.exe`.
+
**Note:** PyPy is currently not supported for 64 bit Python, and translation
will fail in this case.
@@ -264,7 +271,7 @@
Since hacking on PyPy means running tests, you will need a way to specify
the mingw compiler when hacking (as opposed to translating). As of
March 2012, --cc is not a valid option for pytest.py. However if you set an
-environment variable CC to the compliter exe, testing will use it.
+environment variable CC to the compiler exe, testing will use it.
.. _`mingw32 build`: http://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win32/Automated%20Builds
.. _`mingw64 build`: http://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Automated%20Builds
diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py
--- a/pypy/goal/targetpypystandalone.py
+++ b/pypy/goal/targetpypystandalone.py
@@ -258,6 +258,7 @@
enable_translationmodules(config)
config.translation.suggest(check_str_without_nul=True)
+ config.translation.suggest(shared=True)
if config.translation.thread:
config.objspace.usemodules.thread = True
diff --git a/pypy/interpreter/astcompiler/ast.py b/pypy/interpreter/astcompiler/ast.py
--- a/pypy/interpreter/astcompiler/ast.py
+++ b/pypy/interpreter/astcompiler/ast.py
@@ -21,9 +21,11 @@
def get_field(space, w_node, name, optional):
w_obj = w_node.getdictvalue(space, name)
- if w_obj is None and not optional:
- raise oefmt(space.w_TypeError,
+ if w_obj is None:
+ if not optional:
+ raise oefmt(space.w_TypeError,
"required field \"%s\" missing from %T", name, w_node)
+ w_obj = space.w_None
return w_obj
diff --git a/pypy/interpreter/astcompiler/tools/asdl_py.py b/pypy/interpreter/astcompiler/tools/asdl_py.py
--- a/pypy/interpreter/astcompiler/tools/asdl_py.py
+++ b/pypy/interpreter/astcompiler/tools/asdl_py.py
@@ -426,9 +426,11 @@
def get_field(space, w_node, name, optional):
w_obj = w_node.getdictvalue(space, name)
- if w_obj is None and not optional:
- raise oefmt(space.w_TypeError,
+ if w_obj is None:
+ if not optional:
+ raise oefmt(space.w_TypeError,
"required field \"%s\" missing from %T", name, w_node)
+ w_obj = space.w_None
return w_obj
diff --git a/pypy/interpreter/pyparser/pytokenize.py b/pypy/interpreter/pyparser/pytokenize.py
--- a/pypy/interpreter/pyparser/pytokenize.py
+++ b/pypy/interpreter/pyparser/pytokenize.py
@@ -35,8 +35,9 @@
prefix = uniPrefix + rawPrefix
endDFAs[prefix + "'''"] = single3DFA
endDFAs[prefix + '"""'] = double3DFA
-endDFAs["u'''"] = single3DFA
-endDFAs['U"""'] = double3DFA
+for uniPrefix in ("u", "U"):
+ endDFAs[uniPrefix + "'''"] = single3DFA
+ endDFAs[uniPrefix + '"""'] = double3DFA
whiteSpaceStatesAccepts = [True]
whiteSpaceStates = [{'\t': 0, ' ': 0, '\x0c': 0}]
diff --git a/pypy/interpreter/pyparser/test/test_pyparse.py b/pypy/interpreter/pyparser/test/test_pyparse.py
--- a/pypy/interpreter/pyparser/test/test_pyparse.py
+++ b/pypy/interpreter/pyparser/test/test_pyparse.py
@@ -146,6 +146,12 @@
self.parse('a, *rest, b = 1, 2, 3, 4, 5')
self.parse('(a, *rest, b) = 1, 2, 3, 4, 5')
+ def test_u_triple_quote(self):
+ self.parse('u""""""')
+ self.parse('U""""""')
+ self.parse("u''''''")
+ self.parse("U''''''")
+
class TestPythonParserWithSpace:
diff --git a/pypy/module/_ast/test/test_ast.py b/pypy/module/_ast/test/test_ast.py
--- a/pypy/module/_ast/test/test_ast.py
+++ b/pypy/module/_ast/test/test_ast.py
@@ -442,6 +442,11 @@
dict_res = str_node2.__dict__
assert dict_res == {'n':2, 'lineno':2}
+ def test_bug_null_in_objspace_type(self):
+ import ast
+ code = ast.Expression(lineno=1, col_offset=1, body=ast.ListComp(lineno=1, col_offset=1, elt=ast.Call(lineno=1, col_offset=1, func=ast.Name(lineno=1, col_offset=1, id='str', ctx=ast.Load(lineno=1, col_offset=1)), args=[ast.Name(lineno=1, col_offset=1, id='x', ctx=ast.Load(lineno=1, col_offset=1))], keywords=[]), generators=[ast.comprehension(lineno=1, col_offset=1, target=ast.Name(lineno=1, col_offset=1, id='x', ctx=ast.Store(lineno=1, col_offset=1)), iter=ast.List(lineno=1, col_offset=1, elts=[ast.Num(lineno=1, col_offset=1, n=23)], ctx=ast.Load(lineno=1, col_offset=1, )), ifs=[])]))
+ compile(code, '<template>', 'eval')
+
def test_empty_yield_from(self):
# Issue 16546: yield from value is not optional.
import ast
diff --git a/pypy/module/_pypyjson/test/test__pypyjson.py b/pypy/module/_pypyjson/test/test__pypyjson.py
--- a/pypy/module/_pypyjson/test/test__pypyjson.py
+++ b/pypy/module/_pypyjson/test/test__pypyjson.py
@@ -190,6 +190,7 @@
raises(ValueError, "_pypyjson.loads(s)")
def test_raw_encode_basestring_ascii(self):
+ py3k_skip("XXX: needs porting to py3k")
import _pypyjson
def check(s):
s = _pypyjson.raw_encode_basestring_ascii(s)
diff --git a/pypy/module/_socket/__init__.py b/pypy/module/_socket/__init__.py
--- a/pypy/module/_socket/__init__.py
+++ b/pypy/module/_socket/__init__.py
@@ -17,8 +17,6 @@
def startup(self, space):
from rpython.rlib.rsocket import rsocket_startup
rsocket_startup()
- from pypy.module._socket.interp_func import State
- space.fromcache(State).startup(space)
def buildloaders(cls):
from rpython.rlib import rsocket
diff --git a/pypy/module/_socket/interp_func.py b/pypy/module/_socket/interp_func.py
--- a/pypy/module/_socket/interp_func.py
+++ b/pypy/module/_socket/interp_func.py
@@ -1,5 +1,6 @@
from rpython.rlib import rsocket
from rpython.rlib.rsocket import SocketError, INVALID_SOCKET
+from rpython.rlib.rarithmetic import intmask
from pypy.interpreter.error import OperationError
from pypy.interpreter.gateway import unwrap_spec, WrappedDefault
@@ -47,9 +48,8 @@
Return the true host name, a list of aliases, and a list of IP addresses,
for a host. The host argument is a string giving a host name or IP number.
"""
- lock = space.fromcache(State).netdb_lock
try:
- res = rsocket.gethostbyname_ex(host, lock)
+ res = rsocket.gethostbyname_ex(host)
except SocketError, e:
raise converted_error(space, e)
return common_wrapgethost(space, res)
@@ -61,9 +61,8 @@
Return the true host name, a list of aliases, and a list of IP addresses,
for a host. The host argument is a string giving a host name or IP number.
"""
- lock = space.fromcache(State).netdb_lock
try:
- res = rsocket.gethostbyaddr(host, lock)
+ res = rsocket.gethostbyaddr(host)
except SocketError, e:
raise converted_error(space, e)
return common_wrapgethost(space, res)
@@ -177,7 +176,7 @@
Convert a 16-bit integer from network to host byte order.
"""
- return space.wrap(rsocket.ntohs(x))
+ return space.wrap(rsocket.ntohs(intmask(x)))
@unwrap_spec(x="c_uint")
def ntohl(space, x):
@@ -193,7 +192,7 @@
Convert a 16-bit integer from host to network byte order.
"""
- return space.wrap(rsocket.htons(x))
+ return space.wrap(rsocket.htons(intmask(x)))
@unwrap_spec(x="c_uint")
def htonl(space, x):
@@ -325,10 +324,3 @@
raise OperationError(space.w_ValueError,
space.wrap('Timeout value out of range'))
rsocket.setdefaulttimeout(timeout)
-
-class State(object):
- def __init__(self, space):
- self.netdb_lock = None
-
- def startup(self, space):
- self.netdb_lock = space.allocate_lock()
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
@@ -114,10 +114,11 @@
# XXX Hack to seperate rpython and pypy
def make_ushort_port(space, port):
+ assert isinstance(port, int)
if port < 0 or port > 0xffff:
raise OperationError(space.w_OverflowError, space.wrap(
"port must be 0-65535."))
- return rffi.cast(rffi.USHORT, port)
+ return port
def make_unsigned_flowinfo(space, flowinfo):
if flowinfo < 0 or flowinfo > 0xfffff:
@@ -444,8 +445,10 @@
The value argument can either be an integer or a string.
"""
try:
- optval = space.int_w(w_optval)
- except:
+ optval = space.c_int_w(w_optval)
+ except OperationError, e:
+ if e.async(space):
+ raise
optval = space.bytes_w(w_optval)
try:
self.sock.setsockopt(level, optname, optval)
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
@@ -490,6 +490,13 @@
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
reuse = s.getsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR)
assert reuse == 0
+ #
+ raises(TypeError, s.setsockopt, socket.SOL_SOCKET,
+ socket.SO_REUSEADDR, 2 ** 31)
+ raises(TypeError, s.setsockopt, socket.SOL_SOCKET,
+ socket.SO_REUSEADDR, 2 ** 32 + 1)
+ assert s.getsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR) == 0
+ #
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
reuse = s.getsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR)
assert reuse != 0
diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py
--- a/pypy/module/_ssl/interp_ssl.py
+++ b/pypy/module/_ssl/interp_ssl.py
@@ -97,6 +97,8 @@
class SSLContext(W_Root):
+ ctx = lltype.nullptr(SSL_CTX.TO)
+
def __init__(self, space, protocol):
if protocol == PY_SSL_VERSION_TLS1:
method = libssl_TLSv1_method()
diff --git a/pypy/module/_winreg/interp_winreg.py b/pypy/module/_winreg/interp_winreg.py
--- a/pypy/module/_winreg/interp_winreg.py
+++ b/pypy/module/_winreg/interp_winreg.py
@@ -266,10 +266,14 @@
buf = None
if typ == rwinreg.REG_DWORD:
- if space.isinstance_w(w_value, space.w_int):
+ if space.is_none(w_value) or space.isinstance_w(w_value, space.w_int):
+ if space.is_none(w_value):
+ value = r_uint(0)
+ else:
+ value = space.c_uint_w(w_value)
buflen = rffi.sizeof(rwin32.DWORD)
buf1 = lltype.malloc(rffi.CArray(rwin32.DWORD), 1, flavor='raw')
- buf1[0] = space.uint_w(w_value)
+ buf1[0] = value
buf = rffi.cast(rffi.CCHARP, buf1)
elif typ == rwinreg.REG_SZ or typ == rwinreg.REG_EXPAND_SZ:
diff --git a/pypy/module/_winreg/test/test_winreg.py b/pypy/module/_winreg/test/test_winreg.py
--- a/pypy/module/_winreg/test/test_winreg.py
+++ b/pypy/module/_winreg/test/test_winreg.py
@@ -40,7 +40,7 @@
cls.w_tmpfilename = space.wrap(str(udir.join('winreg-temp')))
test_data = [
- ("Int Value", 45, _winreg.REG_DWORD),
+ ("Int Value", 0xFEDCBA98, _winreg.REG_DWORD),
("Str Value", "A string Value", _winreg.REG_SZ),
("Unicode Value", u"A unicode Value", _winreg.REG_SZ),
("Str Expand", "The path is %path%", _winreg.REG_EXPAND_SZ),
@@ -140,9 +140,11 @@
assert 0, "Did not raise"
def test_SetValueEx(self):
- from winreg import CreateKey, SetValueEx, REG_BINARY
+ from winreg import CreateKey, SetValueEx, REG_BINARY, REG_DWORD
key = CreateKey(self.root_key, self.test_key_name)
sub_key = CreateKey(key, "sub_key")
+ SetValueEx(sub_key, 'Int Value', 0, REG_DWORD, None)
+ SetValueEx(sub_key, 'Int Value', 0, REG_DWORD, 45)
for name, value, type in self.test_data:
SetValueEx(sub_key, name, 0, type, value)
exc = raises(TypeError, SetValueEx, sub_key, 'test_name', None,
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
@@ -115,6 +115,8 @@
validate_fd(fileno(fp))
return _feof(fp)
+def is_valid_fp(fp):
+ return is_valid_fd(fileno(fp))
constant_names = """
Py_TPFLAGS_READY Py_TPFLAGS_READYING Py_TPFLAGS_HAVE_GETCHARBUFFER
@@ -465,14 +467,13 @@
# Common types with their own struct
for cpyname, pypyexpr in {
"PyType_Type": "space.w_type",
- "PyString_Type": "space.w_str",
+ "PyBytes_Type": "space.w_bytes",
"PyUnicode_Type": "space.w_unicode",
"PyDict_Type": "space.w_dict",
"PyTuple_Type": "space.w_tuple",
"PyList_Type": "space.w_list",
"PySet_Type": "space.w_set",
"PyFrozenSet_Type": "space.w_frozenset",
- "PyInt_Type": "space.w_int",
"PyBool_Type": "space.w_bool",
"PyFloat_Type": "space.w_float",
"PyLong_Type": "space.w_int",
diff --git a/pypy/module/cpyext/eval.py b/pypy/module/cpyext/eval.py
--- a/pypy/module/cpyext/eval.py
+++ b/pypy/module/cpyext/eval.py
@@ -3,7 +3,7 @@
from rpython.rtyper.lltypesystem import rffi, lltype
from pypy.module.cpyext.api import (
cpython_api, CANNOT_FAIL, CONST_STRING, FILEP, fread, feof, Py_ssize_tP,
- cpython_struct)
+ cpython_struct, is_valid_fp)
from pypy.module.cpyext.pyobject import PyObject, borrow_from
from pypy.module.cpyext.pyerrors import PyErr_SetFromErrno
from pypy.module.cpyext.funcobject import PyCodeObject
@@ -154,6 +154,10 @@
source = ""
filename = rffi.charp2str(filename)
buf = lltype.malloc(rffi.CCHARP.TO, BUF_SIZE, flavor='raw')
+ if not is_valid_fp(fp):
+ lltype.free(buf, flavor='raw')
+ PyErr_SetFromErrno(space, space.w_IOError)
+ return None
try:
while True:
count = fread(buf, 1, BUF_SIZE, fp)
diff --git a/pypy/module/cpyext/include/boolobject.h b/pypy/module/cpyext/include/boolobject.h
--- a/pypy/module/cpyext/include/boolobject.h
+++ b/pypy/module/cpyext/include/boolobject.h
@@ -7,8 +7,6 @@
extern "C" {
#endif
-#define PyBoolObject PyIntObject
-
#define Py_False ((PyObject *) &_Py_ZeroStruct)
#define Py_True ((PyObject *) &_Py_TrueStruct)
diff --git a/pypy/module/cpyext/intobject.py b/pypy/module/cpyext/intobject.py
deleted file mode 100644
--- a/pypy/module/cpyext/intobject.py
+++ /dev/null
@@ -1,162 +0,0 @@
-
-from rpython.rtyper.lltypesystem import rffi, lltype
-from pypy.interpreter.error import OperationError
-from pypy.module.cpyext.api import (
- cpython_api, cpython_struct, build_type_checkers, bootstrap_function,
- PyObject, PyObjectFields, CONST_STRING, CANNOT_FAIL, Py_ssize_t)
-from pypy.module.cpyext.pyobject import (
- make_typedescr, track_reference, RefcountState, from_ref)
-from rpython.rlib.rarithmetic import r_uint, intmask, LONG_TEST, r_ulonglong
-from pypy.objspace.std.intobject import W_IntObject
-import sys
-
-PyIntObjectStruct = lltype.ForwardReference()
-PyIntObject = lltype.Ptr(PyIntObjectStruct)
-PyIntObjectFields = PyObjectFields + \
- (("ob_ival", rffi.LONG),)
-cpython_struct("PyIntObject", PyIntObjectFields, PyIntObjectStruct)
-
- at bootstrap_function
-def init_intobject(space):
- "Type description of PyIntObject"
- make_typedescr(space.w_int.instancetypedef,
- basestruct=PyIntObject.TO,
- attach=int_attach,
- realize=int_realize)
-
-def int_attach(space, py_obj, w_obj):
- """
- Fills a newly allocated PyIntObject with the given int object. The
- value must not be modified.
- """
- py_int = rffi.cast(PyIntObject, py_obj)
- py_int.c_ob_ival = space.int_w(w_obj)
-
-def int_realize(space, obj):
- intval = rffi.cast(lltype.Signed, rffi.cast(PyIntObject, obj).c_ob_ival)
- w_type = from_ref(space, rffi.cast(PyObject, obj.c_ob_type))
- w_obj = space.allocate_instance(W_IntObject, w_type)
- w_obj.__init__(intval)
- track_reference(space, obj, w_obj)
- state = space.fromcache(RefcountState)
- state.set_lifeline(w_obj, obj)
- return w_obj
-
-PyInt_Check, PyInt_CheckExact = build_type_checkers("Int")
-
- at cpython_api([], lltype.Signed, error=CANNOT_FAIL)
-def PyInt_GetMax(space):
- """Return the system's idea of the largest integer it can handle (LONG_MAX,
- as defined in the system header files)."""
- return sys.maxint
-
- at cpython_api([lltype.Signed], PyObject)
-def PyInt_FromLong(space, ival):
- """Create a new integer object with a value of ival.
-
- """
- return space.wrap(ival)
-
- at cpython_api([PyObject], lltype.Signed, error=-1)
-def PyInt_AsLong(space, w_obj):
- """Will first attempt to cast the object to a PyIntObject, if it is not
- already one, and then return its value. If there is an error, -1 is
- returned, and the caller should check PyErr_Occurred() to find out whether
- there was an error, or whether the value just happened to be -1."""
- if w_obj is None:
- raise OperationError(space.w_TypeError,
- space.wrap("an integer is required, got NULL"))
- return space.int_w(space.int(w_obj))
-
- at cpython_api([PyObject], lltype.Unsigned, error=-1)
-def PyInt_AsUnsignedLong(space, w_obj):
- """Return a C unsigned long representation of the contents of pylong.
- If pylong is greater than ULONG_MAX, an OverflowError is
- raised."""
- if w_obj is None:
- raise OperationError(space.w_TypeError,
- space.wrap("an integer is required, got NULL"))
- return space.uint_w(space.int(w_obj))
-
-
- at cpython_api([PyObject], rffi.ULONG, error=-1)
-def PyInt_AsUnsignedLongMask(space, w_obj):
- """Will first attempt to cast the object to a PyIntObject or
- PyLongObject, if it is not already one, and then return its value as
- unsigned long. This function does not check for overflow.
- """
- w_int = space.int(w_obj)
- num = space.bigint_w(w_int)
- return num.uintmask()
-
-
- at cpython_api([PyObject], rffi.ULONGLONG, error=-1)
-def PyInt_AsUnsignedLongLongMask(space, w_obj):
- """Will first attempt to cast the object to a PyIntObject or
- PyLongObject, if it is not already one, and then return its value as
- unsigned long long, without checking for overflow.
- """
- w_int = space.int(w_obj)
- if space.isinstance_w(w_int, space.w_int):
- num = space.int_w(w_int)
- return r_ulonglong(num)
- else:
- num = space.bigint_w(w_int)
- return num.ulonglongmask()
-
- at cpython_api([PyObject], lltype.Signed, error=CANNOT_FAIL)
-def PyInt_AS_LONG(space, w_int):
- """Return the value of the object w_int. No error checking is performed."""
- return space.int_w(w_int)
-
- at cpython_api([PyObject], Py_ssize_t, error=-1)
-def PyInt_AsSsize_t(space, w_obj):
- """Will first attempt to cast the object to a PyIntObject or
- PyLongObject, if it is not already one, and then return its value as
- Py_ssize_t.
- """
- if w_obj is None:
- raise OperationError(space.w_TypeError,
- space.wrap("an integer is required, got NULL"))
- return space.int_w(w_obj) # XXX this is wrong on win64
-
-LONG_MAX = int(LONG_TEST - 1)
-
- at cpython_api([rffi.SIZE_T], PyObject)
-def PyInt_FromSize_t(space, ival):
- """Create a new integer object with a value of ival. If the value exceeds
- LONG_MAX, a long integer object is returned.
- """
- if ival <= LONG_MAX:
- return space.wrap(intmask(ival))
- return space.wrap(ival)
-
- at cpython_api([Py_ssize_t], PyObject)
-def PyInt_FromSsize_t(space, ival):
- """Create a new integer object with a value of ival. If the value is larger
- than LONG_MAX or smaller than LONG_MIN, a long integer object is
- returned.
- """
- return space.wrap(ival)
-
- at cpython_api([CONST_STRING, rffi.CCHARPP, rffi.INT_real], PyObject)
-def PyInt_FromString(space, str, pend, base):
- """Return a new PyIntObject or PyLongObject based on the string
- value in str, which is interpreted according to the radix in base. If
- pend is non-NULL, *pend will point to the first character in str which
- follows the representation of the number. If base is 0, the radix will be
- determined based on the leading characters of str: if str starts with
- '0x' or '0X', radix 16 will be used; if str starts with '0', radix
- 8 will be used; otherwise radix 10 will be used. If base is not 0, it
- must be between 2 and 36, inclusive. Leading spaces are ignored. If
- there are no digits, ValueError will be raised. If the string represents
- a number too large to be contained within the machine's long int type
- and overflow warnings are being suppressed, a PyLongObject will be
- returned. If overflow warnings are not being suppressed, NULL will be
- returned in this case."""
- s = rffi.charp2str(str)
- w_str = space.wrap(s)
- w_base = space.wrap(rffi.cast(lltype.Signed, base))
- if pend:
- pend[0] = rffi.ptradd(str, len(s))
- return space.call_function(space.w_int, w_str, w_base)
diff --git a/pypy/module/cpyext/number.py b/pypy/module/cpyext/number.py
--- a/pypy/module/cpyext/number.py
+++ b/pypy/module/cpyext/number.py
@@ -38,12 +38,6 @@
return space.int_w(w_obj) #XXX: this is wrong on win64
@cpython_api([PyObject], PyObject)
-def PyNumber_Int(space, w_obj):
- """Returns the o converted to an integer object on success, or NULL on failure.
- This is the equivalent of the Python expression int(o)."""
- return space.call_function(space.w_int, w_obj)
-
- at cpython_api([PyObject], PyObject)
def PyNumber_Long(space, w_obj):
"""Returns the o converted to a long integer object on success, or NULL on
failure. This is the equivalent of the Python expression long(o)."""
diff --git a/pypy/module/cpyext/test/test_eval.py b/pypy/module/cpyext/test/test_eval.py
--- a/pypy/module/cpyext/test/test_eval.py
+++ b/pypy/module/cpyext/test/test_eval.py
@@ -89,12 +89,12 @@
rffi.free_charp(buf)
assert 0 == run("42 * 43")
-
+
assert -1 == run("4..3 * 43")
-
+
assert api.PyErr_Occurred()
api.PyErr_Clear()
-
+
def test_run_string(self, space, api):
def run(code, start, w_globals, w_locals):
buf = rffi.str2charp(code)
diff --git a/pypy/module/cpyext/test/test_intobject.py b/pypy/module/cpyext/test/test_intobject.py
deleted file mode 100644
--- a/pypy/module/cpyext/test/test_intobject.py
+++ /dev/null
@@ -1,195 +0,0 @@
-import py.test
-from pypy.module.cpyext.test.test_api import BaseApiTest
-from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
-import sys
-
-py.test.skip("PyInt_ APIs were removed from py3k")
-
-class TestIntObject(BaseApiTest):
- def test_intobject(self, space, api):
- assert api.PyInt_Check(space.wrap(3))
- assert api.PyInt_Check(space.w_True)
- assert not api.PyInt_Check(space.wrap((1, 2, 3)))
- for i in [3, -5, -1, -sys.maxint, sys.maxint - 1]:
- x = api.PyInt_AsLong(space.wrap(i))
- y = api.PyInt_AS_LONG(space.wrap(i))
- assert x == i
- assert y == i
- w_x = api.PyInt_FromLong(x + 1)
- assert space.type(w_x) is space.w_int
- assert space.eq_w(w_x, space.wrap(i + 1))
-
- assert api.PyInt_AsLong(space.w_None) == -1
- assert api.PyErr_Occurred() is space.w_TypeError
- api.PyErr_Clear()
-
- assert api.PyInt_AsLong(None) == -1
- assert api.PyErr_Occurred() is space.w_TypeError
- api.PyErr_Clear()
-
- assert api.PyInt_AsUnsignedLong(space.wrap(sys.maxint)) == sys.maxint
- assert api.PyInt_AsUnsignedLong(space.wrap(-5)) == sys.maxint * 2 + 1
- assert api.PyErr_Occurred() is space.w_ValueError
- api.PyErr_Clear()
-
- assert (api.PyInt_AsUnsignedLongMask(space.wrap(sys.maxint))
- == sys.maxint)
- assert (api.PyInt_AsUnsignedLongMask(space.wrap(10**30))
- == 10**30 % ((sys.maxint + 1) * 2))
-
- assert (api.PyInt_AsUnsignedLongLongMask(space.wrap(sys.maxint))
- == sys.maxint)
- assert (api.PyInt_AsUnsignedLongLongMask(space.wrap(10**30))
- == 10**30 % (2**64))
-
- def test_coerce(self, space, api):
- w_obj = space.appexec([], """():
- class Coerce(object):
- def __int__(self):
- return 42
- return Coerce()""")
- assert api.PyInt_AsLong(w_obj) == 42
-
-class AppTestIntObject(AppTestCpythonExtensionBase):
- def test_fromstring(self):
- module = self.import_extension('foo', [
- ("from_string", "METH_NOARGS",
- """
- return PyInt_FromString("1234", NULL, 16);
- """),
- ])
- assert module.from_string() == 0x1234
- assert type(module.from_string()) is int
-
- def test_size_t(self):
- module = self.import_extension('foo', [
- ("values", "METH_NOARGS",
- """
- return Py_BuildValue("NNNN",
- PyInt_FromSize_t(123),
- PyInt_FromSize_t((size_t)-1),
- PyInt_FromSsize_t(123),
- PyInt_FromSsize_t((size_t)-1));
- """),
- ])
- values = module.values()
- types = [type(x) for x in values]
- assert types == [int, int, int, int]
-
- def test_int_subtype(self):
- module = self.import_extension(
- 'foo', [
- ("newEnum", "METH_VARARGS",
- """
- EnumObject *enumObj;
- long intval;
- PyObject *name;
-
- if (!PyArg_ParseTuple(args, "Oi", &name, &intval))
- return NULL;
-
- PyType_Ready(&Enum_Type);
- enumObj = PyObject_New(EnumObject, &Enum_Type);
- if (!enumObj) {
- return NULL;
- }
-
- enumObj->ob_ival = intval;
- Py_INCREF(name);
- enumObj->ob_name = name;
-
- return (PyObject *)enumObj;
- """),
- ],
- prologue="""
- typedef struct
- {
- PyObject_HEAD
- long ob_ival;
- PyObject* ob_name;
- } EnumObject;
-
- static void
- enum_dealloc(PyObject *op)
- {
- Py_DECREF(((EnumObject *)op)->ob_name);
- Py_TYPE(op)->tp_free(op);
- }
-
- static PyMemberDef enum_members[] = {
- {"name", T_OBJECT, offsetof(EnumObject, ob_name), 0, NULL},
- {NULL} /* Sentinel */
- };
-
- PyTypeObject Enum_Type = {
- PyObject_HEAD_INIT(0)
- /*ob_size*/ 0,
- /*tp_name*/ "Enum",
- /*tp_basicsize*/ sizeof(EnumObject),
- /*tp_itemsize*/ 0,
- /*tp_dealloc*/ enum_dealloc,
- /*tp_print*/ 0,
- /*tp_getattr*/ 0,
- /*tp_setattr*/ 0,
- /*tp_compare*/ 0,
- /*tp_repr*/ 0,
- /*tp_as_number*/ 0,
- /*tp_as_sequence*/ 0,
- /*tp_as_mapping*/ 0,
- /*tp_hash*/ 0,
- /*tp_call*/ 0,
- /*tp_str*/ 0,
- /*tp_getattro*/ 0,
- /*tp_setattro*/ 0,
- /*tp_as_buffer*/ 0,
- /*tp_flags*/ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
- /*tp_doc*/ 0,
- /*tp_traverse*/ 0,
- /*tp_clear*/ 0,
- /*tp_richcompare*/ 0,
- /*tp_weaklistoffset*/ 0,
- /*tp_iter*/ 0,
- /*tp_iternext*/ 0,
- /*tp_methods*/ 0,
- /*tp_members*/ enum_members,
- /*tp_getset*/ 0,
- /*tp_base*/ 0, /* set to &PyInt_Type in init function for MSVC */
- /*tp_dict*/ 0,
- /*tp_descr_get*/ 0,
- /*tp_descr_set*/ 0,
- /*tp_dictoffset*/ 0,
- /*tp_init*/ 0,
- /*tp_alloc*/ 0,
- /*tp_new*/ 0
- };
- """, more_init = '''
- Enum_Type.tp_base = &PyInt_Type;
- ''')
-
- a = module.newEnum("ULTIMATE_ANSWER", 42)
- assert type(a).__name__ == "Enum"
- assert isinstance(a, int)
- assert a == int(a) == 42
- assert a.name == "ULTIMATE_ANSWER"
-
- def test_int_cast(self):
- mod = self.import_extension('foo', [
- #prove it works for ints
- ("test_int", "METH_NOARGS",
- """
- PyObject * obj = PyInt_FromLong(42);
- PyObject * val;
- if (!PyInt_Check(obj)) {
- Py_DECREF(obj);
- PyErr_SetNone(PyExc_ValueError);
- return NULL;
- }
- val = PyInt_FromLong(((PyIntObject *)obj)->ob_ival);
- Py_DECREF(obj);
- return val;
- """
- ),
- ])
- i = mod.test_int()
- assert isinstance(i, int)
- assert i == 42
diff --git a/pypy/module/cpyext/test/test_longobject.py b/pypy/module/cpyext/test/test_longobject.py
--- a/pypy/module/cpyext/test/test_longobject.py
+++ b/pypy/module/cpyext/test/test_longobject.py
@@ -1,6 +1,5 @@
import sys, py
from rpython.rtyper.lltypesystem import rffi, lltype
-from pypy.objspace.std.intobject import W_IntObject
from pypy.objspace.std.longobject import W_LongObject
from pypy.module.cpyext.test.test_api import BaseApiTest
from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
diff --git a/pypy/module/cpyext/test/test_number.py b/pypy/module/cpyext/test/test_number.py
--- a/pypy/module/cpyext/test/test_number.py
+++ b/pypy/module/cpyext/test/test_number.py
@@ -20,14 +20,14 @@
w_l = api.PyNumber_Long(space.wrap("123"))
assert api.PyLong_CheckExact(w_l)
- def test_number_int(self, space, api):
- w_l = api.PyNumber_Int(space.wraplong(123L))
+ def test_number_long2(self, space, api):
+ w_l = api.PyNumber_Long(space.wraplong(123L))
assert api.PyLong_CheckExact(w_l)
- w_l = api.PyNumber_Int(space.wrap(2 << 65))
+ w_l = api.PyNumber_Long(space.wrap(2 << 65))
assert api.PyLong_CheckExact(w_l)
- w_l = api.PyNumber_Int(space.wrap(42.3))
+ w_l = api.PyNumber_Long(space.wrap(42.3))
assert api.PyLong_CheckExact(w_l)
- w_l = api.PyNumber_Int(space.wrap("42"))
+ w_l = api.PyNumber_Long(space.wrap("42"))
assert api.PyLong_CheckExact(w_l)
def test_number_index(self, space, api):
diff --git a/pypy/module/cpyext/test/test_unicodeobject.py b/pypy/module/cpyext/test/test_unicodeobject.py
--- a/pypy/module/cpyext/test/test_unicodeobject.py
+++ b/pypy/module/cpyext/test/test_unicodeobject.py
@@ -219,6 +219,13 @@
assert space.unwrap(w_res) == u'sp�'
rffi.free_charp(s)
+ def test_internfromstring(self, space, api):
+ with rffi.scoped_str2charp('foo') as s:
+ w_res = api.PyUnicode_InternFromString(s)
+ assert space.unwrap(w_res) == u'foo'
+ w_res2 = api.PyUnicode_InternFromString(s)
+ assert w_res is w_res2
+
def test_unicode_resize(self, space, api):
py_uni = new_empty_unicode(space, 10)
ar = lltype.malloc(PyObjectP.TO, 1, flavor='raw')
diff --git a/pypy/module/cpyext/unicodeobject.py b/pypy/module/cpyext/unicodeobject.py
--- a/pypy/module/cpyext/unicodeobject.py
+++ b/pypy/module/cpyext/unicodeobject.py
@@ -508,6 +508,16 @@
w_str = space.wrapbytes(rffi.charp2str(s))
return space.call_method(w_str, 'decode', space.wrap("utf-8"))
+ at cpython_api([CONST_STRING], PyObject)
+def PyUnicode_InternFromString(space, s):
+ """A combination of PyUnicode_FromString() and
+ PyUnicode_InternInPlace(), returning either a new unicode string
+ object that has been interned, or a new ("owned") reference to an
+ earlier interned string object with the same value.
+ """
+ w_str = PyUnicode_FromString(space, s)
+ return space.new_interned_w_str(w_str)
+
@cpython_api([CONST_STRING, Py_ssize_t], PyObject)
def PyUnicode_FromStringAndSize(space, s, size):
"""Create a Unicode Object from the char buffer u. The bytes will be
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
@@ -20,6 +20,7 @@
'concatenate': 'arrayops.concatenate',
'count_nonzero': 'arrayops.count_nonzero',
'dot': 'arrayops.dot',
+ 'result_type': 'arrayops.result_type',
'where': 'arrayops.where',
'set_string_function': 'appbridge.set_string_function',
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
@@ -16,9 +16,9 @@
dtype = test.dtype
length = math.ceil((float(stop) - start) / step)
length = int(length)
- arr = _numpypy.multiarray.zeros(length, dtype=dtype)
+ arr = _numpypy.multiarray.empty(length, dtype=dtype)
i = start
- for j in range(arr.size):
+ for j in xrange(arr.size):
arr[j] = i
i += step
return arr
diff --git a/pypy/module/micronumpy/arrayops.py b/pypy/module/micronumpy/arrayops.py
--- a/pypy/module/micronumpy/arrayops.py
+++ b/pypy/module/micronumpy/arrayops.py
@@ -1,3 +1,4 @@
+from rpython.rlib import jit
from pypy.interpreter.error import OperationError, oefmt
from pypy.interpreter.gateway import unwrap_spec
from pypy.module.micronumpy import loop, descriptor, ufuncs, support, \
@@ -6,6 +7,7 @@
from pypy.module.micronumpy.converters import clipmode_converter
from pypy.module.micronumpy.strides import Chunk, Chunks, shape_agreement, \
shape_agreement_multiple
+from .boxes import W_GenericBox
def where(space, w_arr, w_x=None, w_y=None):
@@ -283,3 +285,28 @@
else:
loop.diagonal_array(space, arr, out, offset, axis1, axis2, shape)
return out
+
+
+ at jit.unroll_safe
+def result_type(space, __args__):
+ args_w, kw_w = __args__.unpack()
+ if kw_w:
+ raise oefmt(space.w_TypeError, "result_type() takes no keyword arguments")
+ if not args_w:
+ raise oefmt(space.w_ValueError, "at least one array or dtype is required")
+ result = None
+ for w_arg in args_w:
+ if isinstance(w_arg, W_NDimArray):
+ dtype = w_arg.get_dtype()
+ elif isinstance(w_arg, W_GenericBox) or (
+ space.isinstance_w(w_arg, space.w_int) or
+ space.isinstance_w(w_arg, space.w_float) or
+ space.isinstance_w(w_arg, space.w_complex) or
+ space.isinstance_w(w_arg, space.w_long) or
+ space.isinstance_w(w_arg, space.w_bool)):
+ dtype = ufuncs.find_dtype_for_scalar(space, w_arg)
+ else:
+ dtype = space.interp_w(descriptor.W_Dtype,
+ space.call_function(space.gettypefor(descriptor.W_Dtype), w_arg))
+ result = ufuncs.find_binop_result_dtype(space, result, dtype)
+ return result
diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py
--- a/pypy/module/micronumpy/compile.py
+++ b/pypy/module/micronumpy/compile.py
@@ -36,7 +36,7 @@
SINGLE_ARG_FUNCTIONS = ["sum", "prod", "max", "min", "all", "any",
"unegative", "flat", "tostring","count_nonzero",
"argsort"]
-TWO_ARG_FUNCTIONS = ["dot", 'take']
+TWO_ARG_FUNCTIONS = ["dot", 'take', 'searchsorted']
TWO_ARG_FUNCTIONS_OR_NONE = ['view', 'astype']
THREE_ARG_FUNCTIONS = ['where']
@@ -109,6 +109,9 @@
if stop < 0:
stop += size + 1
if step < 0:
+ start, stop = stop, start
+ start -= 1
+ stop -= 1
lgt = (stop - start + 1) / step + 1
else:
lgt = (stop - start - 1) / step + 1
@@ -475,7 +478,6 @@
class SliceConstant(Node):
def __init__(self, start, stop, step):
- # no negative support for now
self.start = start
self.stop = stop
self.step = step
@@ -582,6 +584,9 @@
w_res = arr.descr_dot(interp.space, arg)
elif self.name == 'take':
w_res = arr.descr_take(interp.space, arg)
+ elif self.name == "searchsorted":
+ w_res = arr.descr_searchsorted(interp.space, arg,
+ interp.space.wrap('left'))
else:
assert False # unreachable code
elif self.name in THREE_ARG_FUNCTIONS:
diff --git a/pypy/module/micronumpy/concrete.py b/pypy/module/micronumpy/concrete.py
--- a/pypy/module/micronumpy/concrete.py
+++ b/pypy/module/micronumpy/concrete.py
@@ -19,6 +19,7 @@
'strides[*]', 'backstrides[*]', 'order']
start = 0
parent = None
+ flags = 0
# JIT hints that length of all those arrays is a constant
@@ -357,11 +358,11 @@
self.dtype = dtype
def argsort(self, space, w_axis):
- from pypy.module.micronumpy.sort import argsort_array
+ from .selection import argsort_array
return argsort_array(self, space, w_axis)
def sort(self, space, w_axis, w_order):
- from pypy.module.micronumpy.sort import sort_array
+ from .selection import sort_array
return sort_array(self, space, w_axis, w_order)
def base(self):
diff --git a/pypy/module/micronumpy/constants.py b/pypy/module/micronumpy/constants.py
--- a/pypy/module/micronumpy/constants.py
+++ b/pypy/module/micronumpy/constants.py
@@ -65,6 +65,9 @@
FLOATINGLTR = 'f'
COMPLEXLTR = 'c'
+SEARCHLEFT = 0
+SEARCHRIGHT = 1
+
ANYORDER = -1
CORDER = 0
FORTRANORDER = 1
@@ -74,6 +77,9 @@
WRAP = 1
RAISE = 2
+ARRAY_C_CONTIGUOUS = 0x0001
+ARRAY_F_CONTIGUOUS = 0x0002
+
LITTLE = '<'
BIG = '>'
NATIVE = '='
diff --git a/pypy/module/micronumpy/converters.py b/pypy/module/micronumpy/converters.py
--- a/pypy/module/micronumpy/converters.py
+++ b/pypy/module/micronumpy/converters.py
@@ -1,4 +1,4 @@
-from pypy.interpreter.error import OperationError
+from pypy.interpreter.error import OperationError, oefmt
from pypy.module.micronumpy import constants as NPY
@@ -41,6 +41,23 @@
space.wrap("clipmode not understood"))
+def searchside_converter(space, w_obj):
+ try:
+ s = space.str_w(w_obj)
+ except OperationError:
+ s = None
+ if not s:
+ raise oefmt(space.w_ValueError,
+ "expected nonempty string for keyword 'side'")
+ if s[0] == 'l' or s[0] == 'L':
+ return NPY.SEARCHLEFT
+ elif s[0] == 'r' or s[0] == 'R':
+ return NPY.SEARCHRIGHT
+ else:
+ raise oefmt(space.w_ValueError,
+ "'%s' is an invalid value for keyword 'side'", s)
+
+
def order_converter(space, w_order, default):
if space.is_none(w_order):
return default
diff --git a/pypy/module/micronumpy/ctors.py b/pypy/module/micronumpy/ctors.py
--- a/pypy/module/micronumpy/ctors.py
+++ b/pypy/module/micronumpy/ctors.py
@@ -3,7 +3,7 @@
from rpython.rlib.buffer import SubBuffer
from rpython.rlib.rstring import strip_spaces
from rpython.rtyper.lltypesystem import lltype, rffi
-from pypy.module.micronumpy import descriptor, loop
+from pypy.module.micronumpy import descriptor, loop, support
from pypy.module.micronumpy.base import (
W_NDimArray, convert_to_array, W_NumpyObject)
from pypy.module.micronumpy.converters import shape_converter
@@ -134,6 +134,15 @@
if dtype.is_str_or_unicode() and dtype.elsize < 1:
dtype = descriptor.variable_dtype(space, dtype.char + '1')
shape = shape_converter(space, w_shape, dtype)
+ for dim in shape:
+ if dim < 0:
+ raise OperationError(space.w_ValueError, space.wrap(
+ "negative dimensions are not allowed"))
+ try:
+ support.product(shape)
+ except OverflowError:
+ raise OperationError(space.w_ValueError, space.wrap(
+ "array is too big."))
return W_NDimArray.from_shape(space, shape, dtype=dtype, zero=zero)
def empty(space, w_shape, w_dtype=None, w_order=None):
diff --git a/pypy/module/micronumpy/flagsobj.py b/pypy/module/micronumpy/flagsobj.py
--- a/pypy/module/micronumpy/flagsobj.py
+++ b/pypy/module/micronumpy/flagsobj.py
@@ -2,6 +2,46 @@
from pypy.interpreter.error import OperationError
from pypy.interpreter.gateway import interp2app
from pypy.interpreter.typedef import TypeDef, GetSetProperty
+from pypy.module.micronumpy import constants as NPY
+
+
+def enable_flags(arr, flags):
+ arr.flags |= flags
+
+
+def clear_flags(arr, flags):
+ arr.flags &= ~flags
+
+
+def _update_contiguous_flags(arr):
+ shape = arr.shape
+ strides = arr.strides
+
+ is_c_contig = True
+ sd = arr.dtype.elsize
+ for i in range(len(shape) - 1, -1, -1):
+ dim = shape[i]
+ if strides[i] != sd:
+ is_c_contig = False
+ break
+ if dim == 0:
+ break
+ sd *= dim
+ if is_c_contig:
+ enable_flags(arr, NPY.ARRAY_C_CONTIGUOUS)
+ else:
+ clear_flags(arr, NPY.ARRAY_C_CONTIGUOUS)
+
+ sd = arr.dtype.elsize
+ for i in range(len(shape)):
+ dim = shape[i]
+ if strides[i] != sd:
+ clear_flags(arr, NPY.ARRAY_F_CONTIGUOUS)
+ return
+ if dim == 0:
+ break
+ sd *= dim
+ enable_flags(arr, NPY.ARRAY_F_CONTIGUOUS)
class W_FlagsObject(W_Root):
diff --git a/pypy/module/micronumpy/flatiter.py b/pypy/module/micronumpy/flatiter.py
--- a/pypy/module/micronumpy/flatiter.py
+++ b/pypy/module/micronumpy/flatiter.py
@@ -1,7 +1,10 @@
from pypy.interpreter.error import OperationError, oefmt
+from pypy.interpreter.gateway import interp2app
+from pypy.interpreter.typedef import TypeDef, GetSetProperty
from pypy.module.micronumpy import loop
-from pypy.module.micronumpy.base import W_NDimArray, convert_to_array
+from pypy.module.micronumpy.base import convert_to_array
from pypy.module.micronumpy.concrete import BaseConcreteArray
+from .ndarray import W_NDimArray
class FakeArrayImplementation(BaseConcreteArray):
@@ -27,12 +30,22 @@
class W_FlatIterator(W_NDimArray):
def __init__(self, arr):
self.base = arr
+ self.iter, self.state = arr.create_iter()
# this is needed to support W_NDimArray interface
self.implementation = FakeArrayImplementation(self.base)
- self.reset()
- def reset(self):
- self.iter, self.state = self.base.create_iter()
+ def descr_base(self, space):
+ return space.wrap(self.base)
+
+ def descr_index(self, space):
+ return space.wrap(self.state.index)
+
+ def descr_coords(self, space):
+ self.state = self.iter.update(self.state)
+ return space.newtuple([space.wrap(c) for c in self.state.indices])
+
+ def descr_iter(self):
+ return self
def descr_len(self, space):
return space.wrap(self.iter.size)
@@ -44,40 +57,59 @@
self.state = self.iter.next(self.state)
return w_res
- def descr_index(self, space):
- return space.wrap(self.state.index)
-
- def descr_coords(self, space):
- return space.newtuple([space.wrap(c) for c in self.state.indices])
-
def descr_getitem(self, space, w_idx):
if not (space.isinstance_w(w_idx, space.w_int) or
space.isinstance_w(w_idx, space.w_slice)):
raise oefmt(space.w_IndexError, 'unsupported iterator index')
- self.reset()
- base = self.base
- start, stop, step, length = space.decode_index4(w_idx, base.get_size())
- base_iter, base_state = base.create_iter()
- base_state = base_iter.next_skip_x(base_state, start)
- if length == 1:
- return base_iter.getitem(base_state)
- res = W_NDimArray.from_shape(space, [length], base.get_dtype(),
- base.get_order(), w_instance=base)
- return loop.flatiter_getitem(res, base_iter, base_state, step)
+ try:
+ start, stop, step, length = space.decode_index4(w_idx, self.iter.size)
+ state = self.iter.goto(start)
+ if length == 1:
+ return self.iter.getitem(state)
+ base = self.base
+ res = W_NDimArray.from_shape(space, [length], base.get_dtype(),
+ base.get_order(), w_instance=base)
+ return loop.flatiter_getitem(res, self.iter, state, step)
+ finally:
+ self.state = self.iter.reset(self.state)
def descr_setitem(self, space, w_idx, w_value):
if not (space.isinstance_w(w_idx, space.w_int) or
space.isinstance_w(w_idx, space.w_slice)):
raise oefmt(space.w_IndexError, 'unsupported iterator index')
- base = self.base
- start, stop, step, length = space.decode_index4(w_idx, base.get_size())
- arr = convert_to_array(space, w_value)
- loop.flatiter_setitem(space, self.base, arr, start, step, length)
+ start, stop, step, length = space.decode_index4(w_idx, self.iter.size)
+ try:
+ state = self.iter.goto(start)
+ dtype = self.base.get_dtype()
+ if length == 1:
+ try:
+ val = dtype.coerce(space, w_value)
+ except OperationError:
+ raise oefmt(space.w_ValueError, "Error setting single item of array.")
+ self.iter.setitem(state, val)
+ return
+ arr = convert_to_array(space, w_value)
+ loop.flatiter_setitem(space, dtype, arr, self.iter, state, step, length)
+ finally:
+ self.state = self.iter.reset(self.state)
- def descr_iter(self):
- return self
- def descr_base(self, space):
- return space.wrap(self.base)
+W_FlatIterator.typedef = TypeDef("numpy.flatiter",
+ base = GetSetProperty(W_FlatIterator.descr_base),
+ index = GetSetProperty(W_FlatIterator.descr_index),
+ coords = GetSetProperty(W_FlatIterator.descr_coords),
-# typedef is in interp_ndarray, so we see the additional arguments
+ __iter__ = interp2app(W_FlatIterator.descr_iter),
+ __len__ = interp2app(W_FlatIterator.descr_len),
+ next = interp2app(W_FlatIterator.descr_next),
+
+ __getitem__ = interp2app(W_FlatIterator.descr_getitem),
+ __setitem__ = interp2app(W_FlatIterator.descr_setitem),
+
+ __eq__ = interp2app(W_FlatIterator.descr_eq),
+ __ne__ = interp2app(W_FlatIterator.descr_ne),
+ __lt__ = interp2app(W_FlatIterator.descr_lt),
+ __le__ = interp2app(W_FlatIterator.descr_le),
+ __gt__ = interp2app(W_FlatIterator.descr_gt),
+ __ge__ = interp2app(W_FlatIterator.descr_ge),
+)
diff --git a/pypy/module/micronumpy/iterators.py b/pypy/module/micronumpy/iterators.py
--- a/pypy/module/micronumpy/iterators.py
+++ b/pypy/module/micronumpy/iterators.py
@@ -35,14 +35,11 @@
[x.strides[i] * (x.shape[i] - 1) for i in range(len(x.shape))]
we can go faster.
All the calculations happen in next()
-
-next_skip_x(steps) tries to do the iteration for a number of steps at once,
-but then we cannot guarantee that we only overflow one single shape
-dimension, perhaps we could overflow times in one big step.
"""
from rpython.rlib import jit
-from pypy.module.micronumpy import support
+from pypy.module.micronumpy import support, constants as NPY
from pypy.module.micronumpy.base import W_NDimArray
+from pypy.module.micronumpy.flagsobj import _update_contiguous_flags
class PureShapeIter(object):
@@ -80,7 +77,7 @@
class IterState(object):
- _immutable_fields_ = ['iterator', 'index', 'indices[*]', 'offset']
+ _immutable_fields_ = ['iterator', 'index', 'indices', 'offset']
def __init__(self, iterator, index, indices, offset):
self.iterator = iterator
@@ -90,11 +87,18 @@
class ArrayIter(object):
- _immutable_fields_ = ['array', 'size', 'ndim_m1', 'shape_m1[*]',
- 'strides[*]', 'backstrides[*]']
+ _immutable_fields_ = ['contiguous', 'array', 'size', 'ndim_m1', 'shape_m1[*]',
+ 'strides[*]', 'backstrides[*]', 'factors[*]',
+ 'track_index']
+
+ track_index = True
def __init__(self, array, size, shape, strides, backstrides):
assert len(shape) == len(strides) == len(backstrides)
+ _update_contiguous_flags(array)
+ self.contiguous = (array.flags & NPY.ARRAY_C_CONTIGUOUS and
+ array.shape == shape and array.strides == strides)
+
self.array = array
self.size = size
self.ndim_m1 = len(shape) - 1
@@ -102,52 +106,79 @@
self.strides = strides
self.backstrides = backstrides
- def reset(self):
- return IterState(self, 0, [0] * len(self.shape_m1), self.array.start)
+ ndim = len(shape)
+ factors = [0] * ndim
+ for i in xrange(ndim):
+ if i == 0:
+ factors[ndim-1] = 1
+ else:
+ factors[ndim-i-1] = factors[ndim-i] * shape[ndim-i]
+ self.factors = factors
+
+ @jit.unroll_safe
+ def reset(self, state=None):
+ if state is None:
+ indices = [0] * len(self.shape_m1)
+ else:
+ assert state.iterator is self
+ indices = state.indices
+ for i in xrange(self.ndim_m1, -1, -1):
+ indices[i] = 0
+ return IterState(self, 0, indices, self.array.start)
@jit.unroll_safe
def next(self, state):
assert state.iterator is self
- index = state.index + 1
+ index = state.index
+ if self.track_index:
+ index += 1
indices = state.indices
offset = state.offset
- for i in xrange(self.ndim_m1, -1, -1):
- idx = indices[i]
- if idx < self.shape_m1[i]:
- indices[i] = idx + 1
- offset += self.strides[i]
- break
- else:
- indices[i] = 0
- offset -= self.backstrides[i]
+ if self.contiguous:
+ offset += self.array.dtype.elsize
+ else:
+ for i in xrange(self.ndim_m1, -1, -1):
+ idx = indices[i]
+ if idx < self.shape_m1[i]:
+ indices[i] = idx + 1
+ offset += self.strides[i]
+ break
+ else:
+ indices[i] = 0
+ offset -= self.backstrides[i]
return IterState(self, index, indices, offset)
@jit.unroll_safe
- def next_skip_x(self, state, step):
+ def goto(self, index):
+ offset = self.array.start
+ if self.contiguous:
+ offset += index * self.array.dtype.elsize
+ else:
+ current = index
+ for i in xrange(len(self.shape_m1)):
+ offset += (current / self.factors[i]) * self.strides[i]
+ current %= self.factors[i]
+ return IterState(self, index, None, offset)
+
+ @jit.unroll_safe
+ def update(self, state):
assert state.iterator is self
- assert step >= 0
- if step == 0:
+ assert self.track_index
+ if not self.contiguous:
return state
- index = state.index + step
+ current = state.index
indices = state.indices
- offset = state.offset
- for i in xrange(self.ndim_m1, -1, -1):
- idx = indices[i]
- if idx < (self.shape_m1[i] + 1) - step:
- indices[i] = idx + step
- offset += self.strides[i] * step
- break
+ for i in xrange(len(self.shape_m1)):
+ if self.factors[i] != 0:
+ indices[i] = current / self.factors[i]
+ current %= self.factors[i]
else:
- rem_step = (idx + step) // (self.shape_m1[i] + 1)
- cur_step = step - rem_step * (self.shape_m1[i] + 1)
- indices[i] = idx + cur_step
- offset += self.strides[i] * cur_step
- step = rem_step
- assert step > 0
- return IterState(self, index, indices, offset)
+ indices[i] = 0
+ return IterState(self, state.index, indices, state.offset)
def done(self, state):
assert state.iterator is self
+ assert self.track_index
return state.index >= self.size
def getitem(self, state):
diff --git a/pypy/module/micronumpy/loop.py b/pypy/module/micronumpy/loop.py
--- a/pypy/module/micronumpy/loop.py
+++ b/pypy/module/micronumpy/loop.py
@@ -48,6 +48,7 @@
left_iter, left_state = w_lhs.create_iter(shape)
right_iter, right_state = w_rhs.create_iter(shape)
out_iter, out_state = out.create_iter(shape)
+ left_iter.track_index = right_iter.track_index = False
shapelen = len(shape)
while not out_iter.done(out_state):
call2_driver.jit_merge_point(shapelen=shapelen, func=func,
@@ -71,6 +72,7 @@
out = W_NDimArray.from_shape(space, shape, res_dtype, w_instance=w_obj)
obj_iter, obj_state = w_obj.create_iter(shape)
out_iter, out_state = out.create_iter(shape)
+ obj_iter.track_index = False
shapelen = len(shape)
while not out_iter.done(out_state):
call1_driver.jit_merge_point(shapelen=shapelen, func=func,
@@ -182,6 +184,9 @@
iter, state = y_iter, y_state
else:
iter, state = x_iter, x_state
+ out_iter.track_index = x_iter.track_index = False
+ arr_iter.track_index = y_iter.track_index = False
+ iter.track_index = True
shapelen = len(shape)
while not iter.done(state):
where_driver.jit_merge_point(shapelen=shapelen, dtype=dtype,
@@ -229,6 +234,7 @@
dtype=dtype)
assert not arr_iter.done(arr_state)
w_val = arr_iter.getitem(arr_state).convert_to(space, dtype)
+ out_state = out_iter.update(out_state)
if out_state.indices[axis] == 0:
if identity is not None:
w_val = func(dtype, identity, w_val)
@@ -298,6 +304,7 @@
assert left_shape[-1] == right_shape[right_critical_dim]
assert result.get_dtype() == dtype
outi, outs = result.create_iter()
+ outi.track_index = False
lefti = AllButAxisIter(left_impl, len(left_shape) - 1)
righti = AllButAxisIter(right_impl, right_critical_dim)
lefts = lefti.reset()
@@ -322,7 +329,7 @@
outi.setitem(outs, oval)
outs = outi.next(outs)
rights = righti.next(rights)
- rights = righti.reset()
+ rights = righti.reset(rights)
lefts = lefti.next(lefts)
return result
@@ -360,6 +367,7 @@
while not arr_iter.done(arr_state):
nonzero_driver.jit_merge_point(shapelen=shapelen, dims=dims, dtype=dtype)
if arr_iter.getitem_bool(arr_state):
+ arr_state = arr_iter.update(arr_state)
for d in dims:
res_iter.setitem(res_state, box(arr_state.indices[d]))
res_state = res_iter.next(res_state)
@@ -435,7 +443,7 @@
while not ri.done(rs):
flatiter_getitem_driver.jit_merge_point(dtype=dtype)
ri.setitem(rs, base_iter.getitem(base_state))
- base_state = base_iter.next_skip_x(base_state, step)
+ base_state = base_iter.goto(base_state.index + step)
rs = ri.next(rs)
return res
@@ -443,11 +451,8 @@
greens = ['dtype'],
reds = 'auto')
-def flatiter_setitem(space, arr, val, start, step, length):
- dtype = arr.get_dtype()
- arr_iter, arr_state = arr.create_iter()
+def flatiter_setitem(space, dtype, val, arr_iter, arr_state, step, length):
val_iter, val_state = val.create_iter()
- arr_state = arr_iter.next_skip_x(arr_state, start)
while length > 0:
flatiter_setitem_driver.jit_merge_point(dtype=dtype)
val = val_iter.getitem(val_state)
@@ -456,9 +461,10 @@
else:
val = val.convert_to(space, dtype)
arr_iter.setitem(arr_state, val)
- # need to repeat i_nput values until all assignments are done
- arr_state = arr_iter.next_skip_x(arr_state, step)
+ arr_state = arr_iter.goto(arr_state.index + step)
val_state = val_iter.next(val_state)
+ if val_iter.done(val_state):
+ val_state = val_iter.reset(val_state)
length -= 1
fromstring_driver = jit.JitDriver(name = 'numpy_fromstring',
@@ -694,3 +700,43 @@
out_iter.setitem(out_state, arr.getitem_index(space, indexes))
iter.next()
out_state = out_iter.next(out_state)
+
+def _new_binsearch(side, op_name):
+ binsearch_driver = jit.JitDriver(name='numpy_binsearch_' + side,
+ greens=['dtype'],
+ reds='auto')
+
+ def binsearch(space, arr, key, ret):
+ assert len(arr.get_shape()) == 1
+ dtype = key.get_dtype()
+ op = getattr(dtype.itemtype, op_name)
+ key_iter, key_state = key.create_iter()
+ ret_iter, ret_state = ret.create_iter()
+ ret_iter.track_index = False
+ size = arr.get_size()
+ min_idx = 0
+ max_idx = size
+ last_key_val = key_iter.getitem(key_state)
+ while not key_iter.done(key_state):
+ key_val = key_iter.getitem(key_state)
+ if dtype.itemtype.lt(last_key_val, key_val):
+ max_idx = size
+ else:
+ min_idx = 0
+ max_idx = max_idx + 1 if max_idx < size else size
+ last_key_val = key_val
+ while min_idx < max_idx:
+ binsearch_driver.jit_merge_point(dtype=dtype)
+ mid_idx = min_idx + ((max_idx - min_idx) >> 1)
+ mid_val = arr.getitem(space, [mid_idx]).convert_to(space, dtype)
+ if op(mid_val, key_val):
+ min_idx = mid_idx + 1
+ else:
+ max_idx = mid_idx
+ ret_iter.setitem(ret_state, ret.get_dtype().box(min_idx))
+ ret_state = ret_iter.next(ret_state)
+ key_state = key_iter.next(key_state)
+ return binsearch
+
+binsearch_left = _new_binsearch('left', 'lt')
+binsearch_right = _new_binsearch('right', 'le')
diff --git a/pypy/module/micronumpy/ndarray.py b/pypy/module/micronumpy/ndarray.py
--- a/pypy/module/micronumpy/ndarray.py
+++ b/pypy/module/micronumpy/ndarray.py
@@ -16,9 +16,8 @@
ArrayArgumentException, wrap_impl
from pypy.module.micronumpy.concrete import BaseConcreteArray
from pypy.module.micronumpy.converters import multi_axis_converter, \
- order_converter, shape_converter
+ order_converter, shape_converter, searchside_converter
from pypy.module.micronumpy.flagsobj import W_FlagsObject
-from pypy.module.micronumpy.flatiter import W_FlatIterator
from pypy.module.micronumpy.strides import get_shape_from_iterable, \
shape_agreement, shape_agreement_multiple
@@ -407,8 +406,19 @@
--------
numpy.swapaxes : equivalent function
"""
- if self.is_scalar():
+ if axis1 == axis2:
return self
+ n = len(self.get_shape())
+ if n <= 1:
+ return self
+ if axis1 < 0:
+ axis1 += n
+ if axis2 < 0:
+ axis2 += n
+ if axis1 < 0 or axis1 >= n:
+ raise oefmt(space.w_ValueError, "bad axis1 argument to swapaxes")
+ if axis2 < 0 or axis2 >= n:
+ raise oefmt(space.w_ValueError, "bad axis2 argument to swapaxes")
return self.implementation.swapaxes(space, self, axis1, axis2)
def descr_nonzero(self, space):
@@ -464,10 +474,13 @@
return repeat(space, self, repeats, w_axis)
def descr_set_flatiter(self, space, w_obj):
+ iter, state = self.create_iter()
+ dtype = self.get_dtype()
arr = convert_to_array(space, w_obj)
- loop.flatiter_setitem(space, self, arr, 0, 1, self.get_size())
+ loop.flatiter_setitem(space, dtype, arr, iter, state, 1, iter.size)
def descr_get_flatiter(self, space):
+ from .flatiter import W_FlatIterator
return space.wrap(W_FlatIterator(self))
def descr_item(self, space, __args__):
@@ -706,29 +719,22 @@
loop.round(space, self, calc_dtype, self.get_shape(), decimals, out)
return out
- @unwrap_spec(side=str, w_sorter=WrappedDefault(None))
- def descr_searchsorted(self, space, w_v, side='left', w_sorter=None):
+ @unwrap_spec(w_side=WrappedDefault('left'), w_sorter=WrappedDefault(None))
+ def descr_searchsorted(self, space, w_v, w_side=None, w_sorter=None):
if not space.is_none(w_sorter):
raise OperationError(space.w_NotImplementedError, space.wrap(
'sorter not supported in searchsort'))
- if not side or len(side) < 1:
- raise OperationError(space.w_ValueError, space.wrap(
- "expected nonempty string for keyword 'side'"))
- elif side[0] == 'l' or side[0] == 'L':
- side = 'l'
- elif side[0] == 'r' or side[0] == 'R':
- side = 'r'
- else:
- raise oefmt(space.w_ValueError,
- "'%s' is an invalid value for keyword 'side'", side)
- if len(self.get_shape()) > 1:
+ side = searchside_converter(space, w_side)
+ if len(self.get_shape()) != 1:
raise oefmt(space.w_ValueError, "a must be a 1-d array")
v = convert_to_array(space, w_v)
- if len(v.get_shape()) > 1:
- raise oefmt(space.w_ValueError, "v must be a 1-d array-like")
ret = W_NDimArray.from_shape(
space, v.get_shape(), descriptor.get_dtype_cache(space).w_longdtype)
- app_searchsort(space, self, v, space.wrap(side), ret)
+ if side == NPY.SEARCHLEFT:
+ binsearch = loop.binsearch_left
+ else:
+ binsearch = loop.binsearch_right
+ binsearch(space, self, v, ret)
if ret.is_scalar():
return ret.get_scalar_value()
return ret
@@ -1276,31 +1282,6 @@
return res
""", filename=__file__).interphook('ptp')
-app_searchsort = applevel(r"""
- def searchsort(arr, v, side, result):
- import operator
- def func(a, op, val):
- imin = 0
- imax = a.size
- while imin < imax:
- imid = imin + ((imax - imin) >> 1)
- if op(a[imid], val):
- imin = imid +1
- else:
- imax = imid
- return imin
- if side == 'l':
- op = operator.lt
- else:
- op = operator.le
- if v.size < 2:
- result[...] = func(arr, op, v)
- else:
- for i in range(v.size):
- result[i] = func(arr, op, v[i])
- return result
-""", filename=__file__).interphook('searchsort')
-
W_NDimArray.typedef = TypeDef("numpy.ndarray",
__new__ = interp2app(descr_new_array),
@@ -1387,6 +1368,7 @@
flags = GetSetProperty(W_NDimArray.descr_get_flags),
fill = interp2app(W_NDimArray.descr_fill),
+ tobytes = interp2app(W_NDimArray.descr_tostring),
More information about the pypy-commit
mailing list