[pypy-commit] pypy gc-incminimark-pinning: Merge default into gc-incminimark-pinning
groggi
noreply at buildbot.pypy.org
Sun Sep 21 10:09:40 CEST 2014
Author: Gregor Wegberg <code at gregorwegberg.com>
Branch: gc-incminimark-pinning
Changeset: r73625:55c211d937b2
Date: 2014-09-21 10:08 +0200
http://bitbucket.org/pypy/pypy/changeset/55c211d937b2/
Log: Merge default into gc-incminimark-pinning
diff too long, truncating to 2000 out of 5185 lines
diff --git a/_pytest/README-BEFORE-UPDATING b/_pytest/README-BEFORE-UPDATING
new file mode 100644
--- /dev/null
+++ b/_pytest/README-BEFORE-UPDATING
@@ -0,0 +1,17 @@
+This is PyPy's code of the pytest lib. We don't expect to upgrade it
+very often, but once we do:
+
+ WARNING!
+
+ WE HAVE MADE A FEW TWEAKS HERE!
+
+Please be sure that you don't just copy the newer version from
+upstream without checking the few changes that we did. This
+can be done like this:
+
+ cd <this directory>
+ hg log . -v | less
+
+then search for all " _pytest/" in that list to know which are the
+relevant checkins. (Look for the checkins that only edit one
+or two files in this directory.)
diff --git a/_pytest/resultlog.py b/_pytest/resultlog.py
--- a/_pytest/resultlog.py
+++ b/_pytest/resultlog.py
@@ -53,16 +53,24 @@
self.config = config
self.logfile = logfile # preferably line buffered
- def write_log_entry(self, testpath, lettercode, longrepr):
- py.builtin.print_("%s %s" % (lettercode, testpath), file=self.logfile)
+ def write_log_entry(self, testpath, lettercode, longrepr, sections=None):
+ _safeprint("%s %s" % (lettercode, testpath), file=self.logfile)
for line in longrepr.splitlines():
- py.builtin.print_(" %s" % line, file=self.logfile)
+ _safeprint(" %s" % line, file=self.logfile)
+ if sections is not None and (
+ lettercode in ('E', 'F')): # to limit the size of logs
+ for title, content in sections:
+ _safeprint(" ---------- %s ----------" % (title,),
+ file=self.logfile)
+ for line in content.splitlines():
+ _safeprint(" %s" % line, file=self.logfile)
def log_outcome(self, report, lettercode, longrepr):
testpath = getattr(report, 'nodeid', None)
if testpath is None:
testpath = report.fspath
- self.write_log_entry(testpath, lettercode, longrepr)
+ self.write_log_entry(testpath, lettercode, longrepr,
+ getattr(report, 'sections', None))
def pytest_runtest_logreport(self, report):
if report.when != "call" and report.passed:
@@ -98,3 +106,8 @@
if path is None:
path = "cwd:%s" % py.path.local()
self.write_log_entry(path, '!', str(excrepr))
+
+def _safeprint(s, file):
+ if isinstance(s, unicode):
+ s = s.encode('utf-8')
+ py.builtin.print_(s, file=file)
diff --git a/lib-python/2.7/test/test_mmap.py b/lib-python/2.7/test/test_mmap.py
--- a/lib-python/2.7/test/test_mmap.py
+++ b/lib-python/2.7/test/test_mmap.py
@@ -179,25 +179,27 @@
import sys
f = open(TESTFN, "r+b")
try:
- m = mmap.mmap(f.fileno(), mapsize+1)
- except ValueError:
- # we do not expect a ValueError on Windows
- # CAUTION: This also changes the size of the file on disk, and
- # later tests assume that the length hasn't changed. We need to
- # repair that.
+ try:
+ m = mmap.mmap(f.fileno(), mapsize+1)
+ except ValueError:
+ # we do not expect a ValueError on Windows
+ # CAUTION: This also changes the size of the file on disk, and
+ # later tests assume that the length hasn't changed. We need to
+ # repair that.
+ if sys.platform.startswith('win'):
+ self.fail("Opening mmap with size+1 should work on Windows.")
+ else:
+ # we expect a ValueError on Unix, but not on Windows
+ if not sys.platform.startswith('win'):
+ self.fail("Opening mmap with size+1 should raise ValueError.")
+ m.close()
+ finally:
+ f.close()
if sys.platform.startswith('win'):
- self.fail("Opening mmap with size+1 should work on Windows.")
- else:
- # we expect a ValueError on Unix, but not on Windows
- if not sys.platform.startswith('win'):
- self.fail("Opening mmap with size+1 should raise ValueError.")
- m.close()
- f.close()
- if sys.platform.startswith('win'):
- # Repair damage from the resizing test.
- f = open(TESTFN, 'r+b')
- f.truncate(mapsize)
- f.close()
+ # Repair damage from the resizing test.
+ f = open(TESTFN, 'r+b')
+ f.truncate(mapsize)
+ f.close()
# Opening mmap with access=ACCESS_WRITE
f = open(TESTFN, "r+b")
diff --git a/py/README-BEFORE-UPDATING b/py/README-BEFORE-UPDATING
new file mode 100644
--- /dev/null
+++ b/py/README-BEFORE-UPDATING
@@ -0,0 +1,17 @@
+This is PyPy's code of the py lib. We don't expect to upgrade it
+very often, but once we do:
+
+ WARNING!
+
+ WE HAVE MADE A FEW TWEAKS HERE!
+
+Please be sure that you don't just copy the newer version from
+upstream without checking the few changes that we did. This
+can be done like this:
+
+ cd <this directory>
+ hg log . -v | less
+
+then search for all " py/" in that list to know which are the
+relevant checkins. (Look for the checkins that only edit one
+or two files in this directory.)
diff --git a/py/_path/local.py b/py/_path/local.py
--- a/py/_path/local.py
+++ b/py/_path/local.py
@@ -750,7 +750,8 @@
mkdtemp = classmethod(mkdtemp)
def make_numbered_dir(cls, prefix='session-', rootdir=None, keep=3,
- lock_timeout = 172800): # two days
+ lock_timeout = 172800, # two days
+ min_timeout = 300): # five minutes
""" return unique directory with a number greater than the current
maximum one. The number is assumed to start directly after prefix.
if keep is true directories with a number less than (maxnum-keep)
@@ -818,6 +819,20 @@
for path in rootdir.listdir():
num = parse_num(path)
if num is not None and num <= (maxnum - keep):
+ if min_timeout:
+ # NB: doing this is needed to prevent (or reduce
+ # a lot the chance of) the following situation:
+ # 'keep+1' processes call make_numbered_dir() at
+ # the same time, they create dirs, but then the
+ # last process notices the first dir doesn't have
+ # (yet) a .lock in it and kills it.
+ try:
+ t1 = path.lstat().mtime
+ t2 = lockfile.lstat().mtime
+ if abs(t2-t1) < min_timeout:
+ continue # skip directories too recent
+ except py.error.Error:
+ continue # failure to get a time, better skip
lf = path.join('.lock')
try:
t1 = lf.lstat().mtime
diff --git a/pypy/doc/conf.py b/pypy/doc/conf.py
--- a/pypy/doc/conf.py
+++ b/pypy/doc/conf.py
@@ -65,9 +65,9 @@
# built documents.
#
# The short X.Y version.
-version = '2.3'
+version = '2.4'
# The full version, including alpha/beta/rc tags.
-release = '2.3.1'
+release = '2.4.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff --git a/pypy/doc/getting-started-python.rst b/pypy/doc/getting-started-python.rst
--- a/pypy/doc/getting-started-python.rst
+++ b/pypy/doc/getting-started-python.rst
@@ -111,6 +111,10 @@
of your choice. Typical example: ``--opt=2`` gives a good (but of
course slower) Python interpreter without the JIT.
+ Consider using PyPy instead of CPython in the above command line,
+ as it is much faster. (Note that ``rpython`` is a Python 2 program,
+ not Python 3; you need to run either PyPy 2 or CPython 2.)
+
.. _`optimization level`: config/opt.html
If everything works correctly this will create an executable
diff --git a/pypy/doc/index-of-release-notes.rst b/pypy/doc/index-of-release-notes.rst
--- a/pypy/doc/index-of-release-notes.rst
+++ b/pypy/doc/index-of-release-notes.rst
@@ -6,6 +6,7 @@
.. toctree::
+ release-2.4.0.rst
release-2.3.1.rst
release-2.3.0.rst
release-2.2.1.rst
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.3.1`_: the latest official release
+* `Release 2.4.0`_: 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.3.1`: http://pypy.org/download.html
+.. _`Release 2.4.0`: 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.4.0.rst b/pypy/doc/release-2.4.0.rst
new file mode 100644
--- /dev/null
+++ b/pypy/doc/release-2.4.0.rst
@@ -0,0 +1,119 @@
+=================================================
+PyPy 2.4 - Snow White
+=================================================
+
+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:
+
+ 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! We would like to also point out that in
+September, `the Python Software Foundation`_ will `match funds`_ for
+any donations up to $10k! The three sub-projects are:
+
+* `Py3k`_ (supporting Python 3.x): We have released a Python 3.2.5 compatible version
+ we call PyPy3 2.3.1, and 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
+.. _`the Python Software Foundation`: https://www.python.org/psf/
+.. _`match funds`: http://morepypy.blogspot.com/2014/09/python-software-foundation-matching.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.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
+
+Highlights
+==========
+
+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.
+
+PyPy now uses Python 2.7.8 standard library.
+
+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.
+
+
+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 changes;
+for more information see `whats-new`_:
+
+* 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
+
+* Fix performance regression on ufunc(<scalar>, <scalar>) in numpy
+
+* 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
+
+* Upgrade stdlib from 2.7.5 to 2.7.8
+
+* 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 on June 8
+
+.. _`whats-new`: http://doc.pypy.org/en/latest/whatsnew-2.3.1.html
+.. _resolved: https://bitbucket.org/pypy/pypy/issues?status=resolved
+
+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/release-2.4.rst b/pypy/doc/release-2.4.rst
deleted file mode 100644
--- a/pypy/doc/release-2.4.rst
+++ /dev/null
@@ -1,107 +0,0 @@
-=================================================
-PyPy 2.4 - ????????
-=================================================
-
-We're pleased to announce PyPy 2.4, a significant milestone on it's own right
-and the proud parent of our recent PyPy3 and STM releases.
-
-This release contains several improvements and bugfixes.
-
-You can download the PyPy 2.4 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): We have released a Python 3.2.5 compatable version
- we call PyPy3 2.3.1, and are working toward a Python 3.3 compatable version
-
-* `STM`_ (software transactional memory): We have release a first working version, and
-continue to try out new promising paths of acheiving 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. It's fast (`pypy 2.3 and cpython 2.7.x`_ performance comparison;
-note that cpython's speed has not changed since 2.7.2)
-due to its integrated tracing JIT compiler.
-
-This release supports x86 machines running 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.3 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
-
-Highlights
-==========
-
-Benchmarks improved after internal improvements in string and bytearray handling,
-and a major rewrite of the GIL handling. Many of these improvements are offshoots
-of the STM work.
-
-We merged in Python's 2.7.8 stdlib in a record time of one week, proving the
-maturity of our underlying RPython code base and PyPy interpreter.
-
-We welcomed more than 12 new contributors, and conducted two Google Summer of Code
-projects XXX details?
-
-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 changes;
-for more information see `whats-new`_:
-
-* 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
-
-* Move to a mixed polling and mutex GIL model that make mutli-threaded jitted
- code run *much* faster
-
-* Optimize errno handling in linux
-
-* Remove ctypes pythonapi and ctypes.PyDLL, which never worked on PyPy
-
-* Fix performance regression on ufunc(<scalar>, <scalar>) in numpy
-
-* 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
-
-* Upgrade stdlib from 2.7.5 to 2.7.8
-
-*
-
-* 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
-.. _resolved: https://bitbucket.org/pypy/pypy/issues?status=resolved
-
-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-2.4.0.rst b/pypy/doc/whatsnew-2.4.0.rst
new file mode 100644
--- /dev/null
+++ b/pypy/doc/whatsnew-2.4.0.rst
@@ -0,0 +1,66 @@
+=======================
+What's new in PyPy 2.4+
+=======================
+
+.. this is a revision shortly after release-2.3.x
+.. startrev: ca9b7cf02cf4
+
+.. branch: fix-bytearray-complexity
+Bytearray operations no longer copy the bytearray unnecessarily
+
+Added support for ``__getitem__``, ``__setitem__``, ``__getslice__``,
+``__setslice__``, and ``__len__`` to RPython
+
+.. branch: stringbuilder2-perf
+Give the StringBuilder a more flexible internal structure, with a
+chained list of strings instead of just one string. This make it
+more efficient when building large strings, e.g. with cStringIO().
+
+Also, use systematically jit.conditional_call() instead of regular
+branches. This lets the JIT make more linear code, at the cost of
+forcing a bit more data (to be passed as arguments to
+conditional_calls). I would expect the net result to be a slight
+slow-down on some simple benchmarks and a speed-up on bigger
+programs.
+
+.. branch: ec-threadlocal
+Change the executioncontext's lookup to be done by reading a thread-
+local variable (which is implemented in C using '__thread' if
+possible, and pthread_getspecific() otherwise). On Linux x86 and
+x86-64, the JIT backend has a special optimization that lets it emit
+directly a single MOV from a %gs- or %fs-based address. It seems
+actually to give a good boost in performance.
+
+.. branch: fast-gil
+A faster way to handle the GIL, particularly in JIT code. The GIL is
+now a composite of two concepts: a global number (it's just set from
+1 to 0 and back around CALL_RELEASE_GIL), and a real mutex. If there
+are threads waiting to acquire the GIL, one of them is actively
+checking the global number every 0.1 ms to 1 ms. Overall, JIT loops
+full of external function calls now run a bit faster (if no thread was
+started yet), or a *lot* faster (if threads were started already).
+
+.. branch: jit-get-errno
+Optimize the errno handling in the JIT, notably around external
+function calls. Linux-only.
+
+.. branch: disable_pythonapi
+Remove non-functioning ctypes.pyhonapi and ctypes.PyDLL, document this
+incompatibility with cpython. Recast sys.dllhandle to an int.
+
+.. branch: scalar-operations
+Fix performance regression on ufunc(<scalar>, <scalar>) in numpy.
+
+.. branch: pytest-25
+Update our copies of py.test and pylib to versions 2.5.2 and 1.4.20,
+respectively.
+
+.. branch: split-ast-classes
+Classes in the ast module are now distinct from structures used by the compiler.
+
+.. branch: stdlib-2.7.8
+Upgrades from 2.7.6 to 2.7.8
+
+.. branch: cpybug-seq-radd-rmul
+Fix issue #1861 - cpython compatability madness
+
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
@@ -1,62 +1,8 @@
+
=======================
-What's new in PyPy 2.4+
+What's new in PyPy 2.5+
=======================
-.. this is a revision shortly after release-2.3.x
-.. startrev: ca9b7cf02cf4
+.. this is a revision shortly after release-2.4.x
+.. startrev: 7026746cbb1b
-.. branch: fix-bytearray-complexity
-Bytearray operations no longer copy the bytearray unnecessarily
-
-Added support for ``__getitem__``, ``__setitem__``, ``__getslice__``,
-``__setslice__``, and ``__len__`` to RPython
-
-.. branch: stringbuilder2-perf
-Give the StringBuilder a more flexible internal structure, with a
-chained list of strings instead of just one string. This make it
-more efficient when building large strings, e.g. with cStringIO().
-
-Also, use systematically jit.conditional_call() instead of regular
-branches. This lets the JIT make more linear code, at the cost of
-forcing a bit more data (to be passed as arguments to
-conditional_calls). I would expect the net result to be a slight
-slow-down on some simple benchmarks and a speed-up on bigger
-programs.
-
-.. branch: ec-threadlocal
-Change the executioncontext's lookup to be done by reading a thread-
-local variable (which is implemented in C using '__thread' if
-possible, and pthread_getspecific() otherwise). On Linux x86 and
-x86-64, the JIT backend has a special optimization that lets it emit
-directly a single MOV from a %gs- or %fs-based address. It seems
-actually to give a good boost in performance.
-
-.. branch: fast-gil
-A faster way to handle the GIL, particularly in JIT code. The GIL is
-now a composite of two concepts: a global number (it's just set from
-1 to 0 and back around CALL_RELEASE_GIL), and a real mutex. If there
-are threads waiting to acquire the GIL, one of them is actively
-checking the global number every 0.1 ms to 1 ms. Overall, JIT loops
-full of external function calls now run a bit faster (if no thread was
-started yet), or a *lot* faster (if threads were started already).
-
-.. branch: jit-get-errno
-Optimize the errno handling in the JIT, notably around external
-function calls. Linux-only.
-
-.. branch: disable_pythonapi
-Remove non-functioning ctypes.pyhonapi and ctypes.PyDLL, document this
-incompatibility with cpython. Recast sys.dllhandle to an int.
-
-.. branch: scalar-operations
-Fix performance regression on ufunc(<scalar>, <scalar>) in numpy.
-
-.. branch: pytest-25
-Update our copies of py.test and pylib to versions 2.5.2 and 1.4.20,
-respectively.
-
-.. branch: split-ast-classes
-Classes in the ast module are now distinct from structures used by the compiler.
-
-.. branch: stdlib-2.7.8
-Upgrades from 2.7.6 to 2.7.8
diff --git a/pypy/doc/windows.rst b/pypy/doc/windows.rst
--- a/pypy/doc/windows.rst
+++ b/pypy/doc/windows.rst
@@ -85,10 +85,13 @@
Abridged method (for -Ojit builds using Visual Studio 2008)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Download the versions of all the external packages
-from
+Download the versions of all the external packages from
+https://bitbucket.org/pypy/pypy/downloads/local_2.4.zip
+(for 2.4 release and later) or
https://bitbucket.org/pypy/pypy/downloads/local.zip
-Then expand it into the base directory (base_dir) and modify your environment to reflect this::
+(for pre-2.4 versions)
+Then expand it into the base directory (base_dir) and modify your environment
+to reflect this::
set PATH=<base_dir>\bin;<base_dir>\tcltk\bin;%PATH%
set INCLUDE=<base_dir>\include;<base_dir>\tcltk\include;%INCLUDE%
diff --git a/pypy/interpreter/module.py b/pypy/interpreter/module.py
--- a/pypy/interpreter/module.py
+++ b/pypy/interpreter/module.py
@@ -29,6 +29,17 @@
space.w_None)
self.startup_called = False
+ def _cleanup_(self):
+ """Called by the annotator on prebuilt Module instances.
+ We don't have many such modules, but for the ones that
+ show up, remove their __file__ rather than translate it
+ statically inside the executable."""
+ try:
+ space = self.space
+ space.delitem(self.w_dict, space.wrap('__file__'))
+ except OperationError:
+ pass
+
def install(self):
"""NOT_RPYTHON: installs this module into space.builtin_modules"""
w_mod = self.space.wrap(self)
diff --git a/pypy/interpreter/pycode.py b/pypy/interpreter/pycode.py
--- a/pypy/interpreter/pycode.py
+++ b/pypy/interpreter/pycode.py
@@ -38,18 +38,15 @@
def cpython_code_signature(code):
"([list-of-arg-names], vararg-name-or-None, kwarg-name-or-None)."
argcount = code.co_argcount
+ varnames = code.co_varnames
assert argcount >= 0 # annotator hint
- argnames = list(code.co_varnames[:argcount])
+ argnames = list(varnames[:argcount])
if code.co_flags & CO_VARARGS:
- varargname = code.co_varnames[argcount]
+ varargname = varnames[argcount]
argcount += 1
else:
varargname = None
- if code.co_flags & CO_VARKEYWORDS:
- kwargname = code.co_varnames[argcount]
- argcount += 1
- else:
- kwargname = None
+ kwargname = varnames[argcount] if code.co_flags & CO_VARKEYWORDS else None
return Signature(argnames, varargname, kwargname)
diff --git a/pypy/interpreter/pyparser/parsestring.py b/pypy/interpreter/pyparser/parsestring.py
--- a/pypy/interpreter/pyparser/parsestring.py
+++ b/pypy/interpreter/pyparser/parsestring.py
@@ -83,12 +83,6 @@
v = PyString_DecodeEscape(space, substr, 'strict', enc)
return space.wrap(v)
-def hexbyte(val):
- result = "%x" % val
- if len(result) == 1:
- result = "0" + result
- return result
-
def decode_unicode_utf8(space, s, ps, q):
# ****The Python 2.7 version, producing UTF-32 escapes****
# String is utf8-encoded, but 'unicode_escape' expects
@@ -108,15 +102,14 @@
# instead.
lis.append("u005c")
if ord(s[ps]) & 0x80: # XXX inefficient
- w, ps = decode_utf8(space, s, ps, end, "utf-32-be")
- rn = len(w)
- assert rn % 4 == 0
- for i in range(0, rn, 4):
- lis.append('\\U')
- lis.append(hexbyte(ord(w[i])))
- lis.append(hexbyte(ord(w[i+1])))
- lis.append(hexbyte(ord(w[i+2])))
- lis.append(hexbyte(ord(w[i+3])))
+ w, ps = decode_utf8(space, s, ps, end)
+ for c in w:
+ # The equivalent of %08x, which is not supported by RPython.
+ # 7 zeroes are enough for the unicode range, and the
+ # result still fits in 32-bit.
+ hexa = hex(ord(c) + 0x10000000)
+ lis.append('\\U0')
+ lis.append(hexa[3:]) # Skip 0x and the leading 1
else:
lis.append(s[ps])
ps += 1
@@ -136,7 +129,7 @@
# note that the C code has a label here.
# the logic is the same.
if recode_encoding and ord(s[ps]) & 0x80:
- w, ps = decode_utf8(space, s, ps, end, recode_encoding)
+ w, ps = decode_utf8_recode(space, s, ps, end, recode_encoding)
# Append bytes to output buffer.
builder.append(w)
else:
@@ -222,14 +215,18 @@
ch >= 'A' and ch <= 'F')
-def decode_utf8(space, s, ps, end, encoding):
+def decode_utf8(space, s, ps, end):
assert ps >= 0
pt = ps
# while (s < end && *s != '\\') s++; */ /* inefficient for u".."
while ps < end and ord(s[ps]) & 0x80:
ps += 1
- w_u = space.wrap(unicodehelper.decode_utf8(space, s[pt:ps]))
- w_v = unicodehelper.encode(space, w_u, encoding)
+ u = unicodehelper.decode_utf8(space, s[pt:ps])
+ return u, ps
+
+def decode_utf8_recode(space, s, ps, end, recode_encoding):
+ u, ps = decode_utf8(space, s, ps, end)
+ w_v = unicodehelper.encode(space, space.wrap(u), recode_encoding)
v = space.str_w(w_v)
return v, ps
diff --git a/pypy/interpreter/pyparser/test/test_parsestring.py b/pypy/interpreter/pyparser/test/test_parsestring.py
--- a/pypy/interpreter/pyparser/test/test_parsestring.py
+++ b/pypy/interpreter/pyparser/test/test_parsestring.py
@@ -73,11 +73,11 @@
def test_simple_enc_roundtrip(self):
space = self.space
- s = "'\x81'"
+ s = "'\x81\\t'"
s = s.decode("koi8-u").encode("utf8")
w_ret = parsestring.parsestr(self.space, 'koi8-u', s)
ret = space.unwrap(w_ret)
- assert ret == eval("# -*- coding: koi8-u -*-\n'\x81'")
+ assert ret == eval("# -*- coding: koi8-u -*-\n'\x81\\t'")
def test_multiline_unicode_strings_with_backslash(self):
space = self.space
diff --git a/pypy/interpreter/test/test_app_main.py b/pypy/interpreter/test/test_app_main.py
--- a/pypy/interpreter/test/test_app_main.py
+++ b/pypy/interpreter/test/test_app_main.py
@@ -945,7 +945,7 @@
prefix = udir.join('pathtest').ensure(dir=1)
fake_exe = 'bin/pypy-c'
if sys.platform == 'win32':
- fake_exe += '.exe'
+ fake_exe = 'pypy-c.exe'
fake_exe = prefix.join(fake_exe).ensure(file=1)
expected_path = [str(prefix.join(subdir).ensure(dir=1))
for subdir in ('lib_pypy',
@@ -985,6 +985,13 @@
assert sys.path == old_sys_path + [self.goal_dir]
app_main.setup_bootstrap_path(self.fake_exe)
+ if not sys.platform == 'win32':
+ # an existing file is always 'executable' on windows
+ assert sys.executable == '' # not executable!
+ assert sys.path == old_sys_path + [self.goal_dir]
+
+ os.chmod(self.fake_exe, 0755)
+ app_main.setup_bootstrap_path(self.fake_exe)
assert sys.executable == self.fake_exe
assert self.goal_dir not in sys.path
diff --git a/pypy/interpreter/test/test_module.py b/pypy/interpreter/test/test_module.py
--- a/pypy/interpreter/test/test_module.py
+++ b/pypy/interpreter/test/test_module.py
@@ -1,4 +1,5 @@
-
+import py
+from pypy.interpreter.error import OperationError
from pypy.interpreter.module import Module
class TestModule:
@@ -17,6 +18,18 @@
space.raises_w(space.w_AttributeError,
space.delattr, w_m, w('x'))
+ def test___file__(self, space):
+ w = space.wrap
+ m = Module(space, space.wrap('m'))
+ py.test.raises(OperationError, space.getattr, w(m), w('__file__'))
+ m._cleanup_()
+ py.test.raises(OperationError, space.getattr, w(m), w('__file__'))
+ space.setattr(w(m), w('__file__'), w('m.py'))
+ space.getattr(w(m), w('__file__')) # does not raise
+ m._cleanup_()
+ py.test.raises(OperationError, space.getattr, w(m), w('__file__'))
+
+
class AppTest_ModuleObject:
def test_attr(self):
m = __import__('__builtin__')
diff --git a/pypy/interpreter/unicodehelper.py b/pypy/interpreter/unicodehelper.py
--- a/pypy/interpreter/unicodehelper.py
+++ b/pypy/interpreter/unicodehelper.py
@@ -5,6 +5,7 @@
@specialize.memo()
def decode_error_handler(space):
+ # Fast version of the "strict" errors handler.
def raise_unicode_exception_decode(errors, encoding, msg, s,
startingpos, endingpos):
raise OperationError(space.w_UnicodeDecodeError,
@@ -17,6 +18,7 @@
@specialize.memo()
def encode_error_handler(space):
+ # Fast version of the "strict" errors handler.
def raise_unicode_exception_encode(errors, encoding, msg, u,
startingpos, endingpos):
raise OperationError(space.w_UnicodeEncodeError,
diff --git a/pypy/module/_cffi_backend/ctypefunc.py b/pypy/module/_cffi_backend/ctypefunc.py
--- a/pypy/module/_cffi_backend/ctypefunc.py
+++ b/pypy/module/_cffi_backend/ctypefunc.py
@@ -8,6 +8,7 @@
from rpython.rlib.jit_libffi import (CIF_DESCRIPTION, CIF_DESCRIPTION_P,
FFI_TYPE, FFI_TYPE_P, FFI_TYPE_PP, SIZE_OF_FFI_ARG)
from rpython.rlib.objectmodel import we_are_translated, instantiate
+from rpython.rlib.objectmodel import keepalive_until_here
from rpython.rtyper.lltypesystem import lltype, llmemory, rffi
from pypy.interpreter.error import OperationError, oefmt
@@ -160,6 +161,7 @@
raw_cdata = rffi.cast(rffi.CCHARPP, data)[0]
lltype.free(raw_cdata, flavor='raw')
lltype.free(buffer, flavor='raw')
+ keepalive_until_here(args_w)
return w_res
def get_mustfree_flag(data):
diff --git a/pypy/module/_cffi_backend/ctypeprim.py b/pypy/module/_cffi_backend/ctypeprim.py
--- a/pypy/module/_cffi_backend/ctypeprim.py
+++ b/pypy/module/_cffi_backend/ctypeprim.py
@@ -182,8 +182,12 @@
value = misc.read_raw_long_data(cdata, self.size)
return self.space.wrap(value)
else:
- value = misc.read_raw_signed_data(cdata, self.size)
- return self.space.wrap(value) # r_longlong => on 32-bit, 'long'
+ return self._convert_to_object_longlong(cdata)
+
+ def _convert_to_object_longlong(self, cdata):
+ # in its own function: LONGLONG may make the whole function jit-opaque
+ value = misc.read_raw_signed_data(cdata, self.size)
+ return self.space.wrap(value) # r_longlong => on 32-bit, 'long'
def convert_from_object(self, cdata, w_ob):
if self.value_fits_long:
@@ -193,8 +197,12 @@
self._overflow(w_ob)
misc.write_raw_signed_data(cdata, value, self.size)
else:
- value = misc.as_long_long(self.space, w_ob)
- misc.write_raw_signed_data(cdata, value, self.size)
+ self._convert_from_object_longlong(cdata, w_ob)
+
+ def _convert_from_object_longlong(self, cdata, w_ob):
+ # in its own function: LONGLONG may make the whole function jit-opaque
+ value = misc.as_long_long(self.space, w_ob)
+ misc.write_raw_signed_data(cdata, value, self.size)
def get_vararg_type(self):
if self.size < rffi.sizeof(rffi.INT):
@@ -264,8 +272,12 @@
self._overflow(w_ob)
misc.write_raw_unsigned_data(cdata, value, self.size)
else:
- value = misc.as_unsigned_long_long(self.space, w_ob, strict=True)
- misc.write_raw_unsigned_data(cdata, value, self.size)
+ self._convert_from_object_longlong(cdata, w_ob)
+
+ def _convert_from_object_longlong(self, cdata, w_ob):
+ # in its own function: LONGLONG may make the whole function jit-opaque
+ value = misc.as_unsigned_long_long(self.space, w_ob, strict=True)
+ misc.write_raw_unsigned_data(cdata, value, self.size)
def convert_to_object(self, cdata):
if self.value_fits_ulong:
@@ -275,8 +287,12 @@
else:
return self.space.wrap(value) # r_uint => 'long' object
else:
- value = misc.read_raw_unsigned_data(cdata, self.size)
- return self.space.wrap(value) # r_ulonglong => 'long' object
+ return self._convert_to_object_longlong(cdata)
+
+ def _convert_to_object_longlong(self, cdata):
+ # in its own function: LONGLONG may make the whole function jit-opaque
+ value = misc.read_raw_unsigned_data(cdata, self.size)
+ return self.space.wrap(value) # r_ulonglong => 'long' object
def get_vararg_type(self):
if self.size < rffi.sizeof(rffi.INT):
diff --git a/pypy/module/_cffi_backend/ctypestruct.py b/pypy/module/_cffi_backend/ctypestruct.py
--- a/pypy/module/_cffi_backend/ctypestruct.py
+++ b/pypy/module/_cffi_backend/ctypestruct.py
@@ -17,7 +17,7 @@
class W_CTypeStructOrUnion(W_CType):
- _immutable_fields_ = ['alignment?', 'fields_list?', 'fields_dict?',
+ _immutable_fields_ = ['alignment?', 'fields_list?[*]', 'fields_dict?',
'custom_field_pos?', 'with_var_array?']
# fields added by complete_struct_or_union():
alignment = -1
diff --git a/pypy/module/_cffi_backend/newtype.py b/pypy/module/_cffi_backend/newtype.py
--- a/pypy/module/_cffi_backend/newtype.py
+++ b/pypy/module/_cffi_backend/newtype.py
@@ -389,7 +389,7 @@
w_ctype.size = totalsize
w_ctype.alignment = totalalignment
- w_ctype.fields_list = fields_list
+ w_ctype.fields_list = fields_list[:]
w_ctype.fields_dict = fields_dict
w_ctype.custom_field_pos = custom_field_pos
w_ctype.with_var_array = with_var_array
diff --git a/pypy/module/_io/interp_stringio.py b/pypy/module/_io/interp_stringio.py
--- a/pypy/module/_io/interp_stringio.py
+++ b/pypy/module/_io/interp_stringio.py
@@ -86,7 +86,7 @@
initval = space.unicode_w(w_initval)
size = len(initval)
self.resize_buffer(size)
- self.buf = [c for c in initval]
+ self.buf = list(initval)
pos = space.getindex_w(w_pos, space.w_TypeError)
if pos < 0:
raise OperationError(space.w_ValueError,
diff --git a/pypy/module/_pypyjson/interp_encoder.py b/pypy/module/_pypyjson/interp_encoder.py
--- a/pypy/module/_pypyjson/interp_encoder.py
+++ b/pypy/module/_pypyjson/interp_encoder.py
@@ -37,16 +37,14 @@
sb = StringBuilder(len(u))
sb.append_slice(s, 0, first)
else:
+ # We used to check if 'u' contains only safe characters, and return
+ # 'w_string' directly. But this requires an extra pass over all
+ # characters, and the expected use case of this function, from
+ # json.encoder, will anyway re-encode a unicode result back to
+ # a string (with the ascii encoding). This requires two passes
+ # over the characters. So we may as well directly turn it into a
+ # string here --- only one pass.
u = space.unicode_w(w_string)
- for i in range(len(u)):
- c = u[i]
- if c >= u' ' and c <= u'~' and c != u'"' and c != u'\\':
- pass
- else:
- break
- else:
- # the input is a unicode with only non-special ascii chars
- return w_string
sb = StringBuilder(len(u))
first = 0
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
@@ -192,14 +192,14 @@
def test_raw_encode_basestring_ascii(self):
import _pypyjson
- def check(s, expected_type=str):
+ def check(s):
s = _pypyjson.raw_encode_basestring_ascii(s)
- assert type(s) is expected_type
+ assert type(s) is str
return s
assert check("") == ""
- assert check(u"", expected_type=unicode) == u""
+ assert check(u"") == ""
assert check("abc ") == "abc "
- assert check(u"abc ", expected_type=unicode) == u"abc "
+ assert check(u"abc ") == "abc "
raises(UnicodeDecodeError, check, "\xc0")
assert check("\xc2\x84") == "\\u0084"
assert check("\xf0\x92\x8d\x85") == "\\ud808\\udf45"
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
@@ -759,17 +759,25 @@
# socket's timeout is in seconds, poll's timeout in ms
timeout = int(sock_timeout * 1000 + 0.5)
- ready = rpoll.poll(fddict, timeout)
+ try:
+ ready = rpoll.poll(fddict, timeout)
+ except rpoll.PollError, e:
+ message = e.get_msg()
+ raise ssl_error(space, message, e.errno)
else:
if MAX_FD_SIZE is not None and sock_fd >= MAX_FD_SIZE:
return SOCKET_TOO_LARGE_FOR_SELECT
- if writing:
- r, w, e = rpoll.select([], [sock_fd], [], sock_timeout)
- ready = w
- else:
- r, w, e = rpoll.select([sock_fd], [], [], sock_timeout)
- ready = r
+ try:
+ if writing:
+ r, w, e = rpoll.select([], [sock_fd], [], sock_timeout)
+ ready = w
+ else:
+ r, w, e = rpoll.select([sock_fd], [], [], sock_timeout)
+ ready = r
+ except rpoll.SelectError as e:
+ message = e.get_msg()
+ raise ssl_error(space, message, e.errno)
if ready:
return SOCKET_OPERATION_OK
else:
diff --git a/pypy/module/cpyext/include/patchlevel.h b/pypy/module/cpyext/include/patchlevel.h
--- a/pypy/module/cpyext/include/patchlevel.h
+++ b/pypy/module/cpyext/include/patchlevel.h
@@ -29,7 +29,7 @@
#define PY_VERSION "2.7.8"
/* PyPy version as a string */
-#define PYPY_VERSION "2.3.1"
+#define PYPY_VERSION "2.5.0-alpha0"
/* Subversion Revision number of this file (not of the repository).
* Empty since Mercurial migration. */
diff --git a/pypy/module/operator/__init__.py b/pypy/module/operator/__init__.py
--- a/pypy/module/operator/__init__.py
+++ b/pypy/module/operator/__init__.py
@@ -39,7 +39,7 @@
'irshift', 'isub', 'itruediv', 'ixor', '_length_hint']
interpleveldefs = {
- '_compare_digest': 'interp_operator.compare_digest',
+ '_compare_digest': 'tscmp.compare_digest',
}
for name in interp_names:
diff --git a/pypy/module/operator/app_operator.py b/pypy/module/operator/app_operator.py
--- a/pypy/module/operator/app_operator.py
+++ b/pypy/module/operator/app_operator.py
@@ -4,7 +4,7 @@
This module exports a set of operators as functions. E.g. operator.add(x,y) is
equivalent to x+y.
'''
-from __pypy__ import builtinify
+
import types
@@ -27,7 +27,7 @@
'getslice(a, b, c) -- Same as a[b:c].'
if not isinstance(start, int) or not isinstance(end, int):
raise TypeError("an integer is expected")
- return a[start:end]
+ return a[start:end]
__getslice__ = getslice
def indexOf(a, b):
@@ -37,7 +37,7 @@
if x == b:
return index
index += 1
- raise ValueError, 'sequence.index(x): x not in sequence'
+ raise ValueError('sequence.index(x): x not in sequence')
def isMappingType(obj,):
'isMappingType(a) -- Return True if a has a mapping type, False otherwise.'
@@ -58,9 +58,9 @@
def repeat(obj, num):
'repeat(a, b) -- Return a * b, where a is a sequence, and b is an integer.'
if not isinstance(num, (int, long)):
- raise TypeError, 'an integer is required'
+ raise TypeError('an integer is required')
if not isSequenceType(obj):
- raise TypeError, "non-sequence object can't be repeated"
+ raise TypeError("non-sequence object can't be repeated")
return obj * num
@@ -68,59 +68,85 @@
def setslice(a, b, c, d):
'setslice(a, b, c, d) -- Same as a[b:c] = d.'
- a[b:c] = d
+ a[b:c] = d
__setslice__ = setslice
+def _resolve_attr_chain(chain, obj, idx=0):
+ obj = getattr(obj, chain[idx])
+ if idx + 1 == len(chain):
+ return obj
+ else:
+ return _resolve_attr_chain(chain, obj, idx + 1)
+
+
+class _simple_attrgetter(object):
+ def __init__(self, attr):
+ self._attr = attr
+
+ def __call__(self, obj):
+ return getattr(obj, self._attr)
+
+
+class _single_attrgetter(object):
+ def __init__(self, attrs):
+ self._attrs = attrs
+
+ def __call__(self, obj):
+ return _resolve_attr_chain(self._attrs, obj)
+
+
+class _multi_attrgetter(object):
+ def __init__(self, attrs):
+ self._attrs = attrs
+
+ def __call__(self, obj):
+ return tuple([
+ _resolve_attr_chain(attrs, obj)
+ for attrs in self._attrs
+ ])
+
+
def attrgetter(attr, *attrs):
+ if (
+ not isinstance(attr, basestring) or
+ not all(isinstance(a, basestring) for a in attrs)
+ ):
+ def _raise_typeerror(obj):
+ raise TypeError(
+ "argument must be a string, not %r" % type(attr).__name__
+ )
+ return _raise_typeerror
if attrs:
- getters = [single_attr_getter(a) for a in (attr,) + attrs]
- def getter(obj):
- return tuple([getter(obj) for getter in getters])
+ return _multi_attrgetter([
+ a.split(".") for a in [attr] + list(attrs)
+ ])
+ elif "." not in attr:
+ return _simple_attrgetter(attr)
else:
- getter = single_attr_getter(attr)
- return builtinify(getter)
+ return _single_attrgetter(attr.split("."))
-def single_attr_getter(attr):
- if not isinstance(attr, str):
- if not isinstance(attr, unicode):
- def _raise_typeerror(obj):
- raise TypeError("argument must be a string, not %r" %
- (type(attr).__name__,))
- return _raise_typeerror
- attr = attr.encode('ascii')
- #
- def make_getter(name, prevfn=None):
- if prevfn is None:
- def getter(obj):
- return getattr(obj, name)
+
+class itemgetter(object):
+ def __init__(self, item, *items):
+ self._single = not bool(items)
+ if self._single:
+ self._idx = item
else:
- def getter(obj):
- return getattr(prevfn(obj), name)
- return getter
- #
- last = 0
- getter = None
- while True:
- dot = attr.find(".", last)
- if dot < 0: break
- getter = make_getter(attr[last:dot], getter)
- last = dot + 1
- return make_getter(attr[last:], getter)
+ self._idx = [item] + list(items)
+ def __call__(self, obj):
+ if self._single:
+ return obj[self._idx]
+ else:
+ return tuple([obj[i] for i in self._idx])
-def itemgetter(item, *items):
- if items:
- list_of_indices = [item] + list(items)
- def getter(obj):
- return tuple([obj[i] for i in list_of_indices])
- else:
- def getter(obj):
- return obj[item]
- return builtinify(getter)
+class methodcaller(object):
+ def __init__(self, method_name, *args, **kwargs):
+ self._method_name = method_name
+ self._args = args
+ self._kwargs = kwargs
-def methodcaller(method_name, *args, **kwargs):
- def call(obj):
- return getattr(obj, method_name)(*args, **kwargs)
- return builtinify(call)
+ def __call__(self, obj):
+ return getattr(obj, self._method_name)(*self._args, **self._kwargs)
diff --git a/pypy/module/operator/interp_operator.py b/pypy/module/operator/interp_operator.py
--- a/pypy/module/operator/interp_operator.py
+++ b/pypy/module/operator/interp_operator.py
@@ -1,6 +1,4 @@
-from rpython.rlib.objectmodel import specialize
-
-from pypy.interpreter.error import OperationError, oefmt
+from pypy.interpreter.error import OperationError
from pypy.interpreter.gateway import unwrap_spec
@@ -249,33 +247,3 @@
@unwrap_spec(default=int)
def _length_hint(space, w_iterable, default):
return space.wrap(space.length_hint(w_iterable, default))
-
-def compare_digest(space, w_a, w_b):
- if (
- space.isinstance_w(w_a, space.w_unicode) and
- space.isinstance_w(w_b, space.w_unicode)
- ):
- return space.wrap(tscmp(space.unicode_w(w_a), space.unicode_w(w_b)))
- if (
- space.isinstance_w(w_a, space.w_unicode) or
- space.isinstance_w(w_b, space.w_unicode)
- ):
- raise oefmt(
- space.w_TypeError,
- "unsupported operand types(s) or combination of types: '%N' and '%N'",
- w_a,
- w_b,
- )
- else:
- return space.wrap(tscmp(space.bufferstr_w(w_a), space.bufferstr_w(w_b)))
-
-
- at specialize.argtype(0, 1)
-def tscmp(a, b):
- len_a = len(a)
- len_b = len(b)
- length = min(len(a), len(b))
- res = len_a ^ len_b
- for i in xrange(length):
- res |= ord(a[i]) ^ ord(b[i])
- return res == 0
diff --git a/pypy/module/operator/test/test_operator.py b/pypy/module/operator/test/test_operator.py
--- a/pypy/module/operator/test/test_operator.py
+++ b/pypy/module/operator/test/test_operator.py
@@ -334,3 +334,9 @@
assert operator._compare_digest(a, b)
a, b = mybytes(b"foobar"), mybytes(b"foobaz")
assert not operator._compare_digest(a, b)
+
+ def test_compare_digest_unicode(self):
+ import operator
+ assert operator._compare_digest(u'asd', u'asd')
+ assert not operator._compare_digest(u'asd', u'qwe')
+ raises(TypeError, operator._compare_digest, u'asd', b'qwe')
diff --git a/pypy/module/operator/test/test_tscmp.py b/pypy/module/operator/test/test_tscmp.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/operator/test/test_tscmp.py
@@ -0,0 +1,28 @@
+from pypy.module.operator.tscmp import pypy_tscmp, pypy_tscmp_wide
+
+class TestTimingSafeCompare:
+ tostr = str
+ tscmp = staticmethod(pypy_tscmp)
+
+ def test_tscmp_neq(self):
+ assert not self.tscmp(self.tostr('asd'), self.tostr('qwe'), 3, 3)
+
+ def test_tscmp_eq(self):
+ assert self.tscmp(self.tostr('asd'), self.tostr('asd'), 3, 3)
+
+ def test_tscmp_len(self):
+ assert self.tscmp(self.tostr('asdp'), self.tostr('asdq'), 3, 3)
+
+ def test_tscmp_nlen(self):
+ assert not self.tscmp(self.tostr('asd'), self.tostr('asd'), 2, 3)
+
+
+class TestTimingSafeCompareWide(TestTimingSafeCompare):
+ tostr = unicode
+ tscmp = staticmethod(pypy_tscmp_wide)
+
+ def test_tscmp_wide_nonascii(self):
+ a, b = u"\ud808\udf45", u"\ud808\udf45"
+ assert self.tscmp(a, b, len(a), len(b))
+ a, b = u"\ud808\udf45", u"\ud808\udf45 "
+ assert not self.tscmp(a, b, len(a), len(b))
diff --git a/pypy/module/operator/tscmp.c b/pypy/module/operator/tscmp.c
new file mode 100644
--- /dev/null
+++ b/pypy/module/operator/tscmp.c
@@ -0,0 +1,80 @@
+/* Derived from CPython 3.3.5's operator.c::_tscmp
+ */
+
+#include <stdlib.h>
+#include <wchar.h>
+#include "tscmp.h"
+
+int
+pypy_tscmp(const char *a, const char *b, long len_a, long len_b)
+{
+ /* The volatile type declarations make sure that the compiler has no
+ * chance to optimize and fold the code in any way that may change
+ * the timing.
+ */
+ volatile long length;
+ volatile const char *left;
+ volatile const char *right;
+ long i;
+ char result;
+
+ /* loop count depends on length of b */
+ length = len_b;
+ left = NULL;
+ right = b;
+
+ /* don't use else here to keep the amount of CPU instructions constant,
+ * volatile forces re-evaluation
+ * */
+ if (len_a == length) {
+ left = *((volatile const char**)&a);
+ result = 0;
+ }
+ if (len_a != length) {
+ left = b;
+ result = 1;
+ }
+
+ for (i=0; i < length; i++) {
+ result |= *left++ ^ *right++;
+ }
+
+ return (result == 0);
+}
+
+int
+pypy_tscmp_wide(const wchar_t *a, const wchar_t *b, long len_a, long len_b)
+{
+ /* The volatile type declarations make sure that the compiler has no
+ * chance to optimize and fold the code in any way that may change
+ * the timing.
+ */
+ volatile long length;
+ volatile const wchar_t *left;
+ volatile const wchar_t *right;
+ long i;
+ wchar_t result;
+
+ /* loop count depends on length of b */
+ length = len_b;
+ left = NULL;
+ right = b;
+
+ /* don't use else here to keep the amount of CPU instructions constant,
+ * volatile forces re-evaluation
+ * */
+ if (len_a == length) {
+ left = *((volatile const wchar_t**)&a);
+ result = 0;
+ }
+ if (len_a != length) {
+ left = b;
+ result = 1;
+ }
+
+ for (i=0; i < length; i++) {
+ result |= *left++ ^ *right++;
+ }
+
+ return (result == 0);
+}
diff --git a/pypy/module/operator/tscmp.h b/pypy/module/operator/tscmp.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/operator/tscmp.h
@@ -0,0 +1,2 @@
+int pypy_tscmp(const char *, const char *, long, long);
+int pypy_tscmp_wide(const wchar_t *, const wchar_t *, long, long);
diff --git a/pypy/module/operator/tscmp.py b/pypy/module/operator/tscmp.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/operator/tscmp.py
@@ -0,0 +1,73 @@
+"""
+Provides _compare_digest method, which is a safe comparing to prevent timing
+attacks for the hmac module.
+"""
+import py
+
+from rpython.rtyper.lltypesystem import lltype, rffi
+from rpython.translator.tool.cbuild import ExternalCompilationInfo
+
+from pypy.interpreter.error import oefmt
+
+cwd = py.path.local(__file__).dirpath()
+eci = ExternalCompilationInfo(
+ includes=[cwd.join('tscmp.h')],
+ include_dirs=[str(cwd)],
+ separate_module_files=[cwd.join('tscmp.c')],
+ export_symbols=['pypy_tscmp', 'pypy_tscmp_wide'])
+
+
+def llexternal(*args, **kwargs):
+ kwargs.setdefault('compilation_info', eci)
+ kwargs.setdefault('sandboxsafe', True)
+ return rffi.llexternal(*args, **kwargs)
+
+
+pypy_tscmp = llexternal(
+ 'pypy_tscmp',
+ [rffi.CCHARP, rffi.CCHARP, rffi.LONG, rffi.LONG],
+ rffi.INT)
+pypy_tscmp_wide = llexternal(
+ 'pypy_tscmp_wide',
+ [rffi.CWCHARP, rffi.CWCHARP, rffi.LONG, rffi.LONG],
+ rffi.INT)
+
+
+def compare_digest(space, w_a, w_b):
+ """compare_digest(a, b) -> bool
+
+ Return 'a == b'. This function uses an approach designed to prevent
+ timing analysis, making it appropriate for cryptography. a and b
+ must both be of the same type: either str (ASCII only), or any type
+ that supports the buffer protocol (e.g. bytes).
+
+ Note: If a and b are of different lengths, or if an error occurs, a
+ timing attack could theoretically reveal information about the types
+ and lengths of a and b--but not their values.
+ """
+ if (space.isinstance_w(w_a, space.w_unicode) and
+ space.isinstance_w(w_b, space.w_unicode)):
+ a = space.unicode_w(w_a)
+ b = space.unicode_w(w_b)
+ with rffi.scoped_nonmoving_unicodebuffer(a) as a_buf:
+ with rffi.scoped_nonmoving_unicodebuffer(b) as b_buf:
+ result = pypy_tscmp_wide(a_buf, b_buf, len(a), len(b))
+ return space.wrap(rffi.cast(lltype.Bool, result))
+ return compare_digest_buffer(space, w_a, w_b)
+
+
+def compare_digest_buffer(space, w_a, w_b):
+ try:
+ a_buf = w_a.buffer_w(space, space.BUF_SIMPLE)
+ b_buf = w_b.buffer_w(space, space.BUF_SIMPLE)
+ except TypeError:
+ raise oefmt(space.w_TypeError,
+ "unsupported operand types(s) or combination of types: "
+ "'%T' and '%T'", w_a, w_b)
+
+ a = a_buf.as_str()
+ b = b_buf.as_str()
+ with rffi.scoped_nonmovingbuffer(a) as a_buf:
+ with rffi.scoped_nonmovingbuffer(b) as b_buf:
+ result = pypy_tscmp(a_buf, b_buf, len(a), len(b))
+ return space.wrap(rffi.cast(lltype.Bool, result))
diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py
--- a/pypy/module/pypyjit/test_pypy_c/test_call.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_call.py
@@ -17,13 +17,18 @@
# now we can inline it as call assembler
i = 0
j = 0
- while i < 20:
+ while i < 25:
i += 1
j += rec(100) # ID: call_rec
return j
#
- log = self.run(fn, [], threshold=18)
- loop, = log.loops_by_filename(self.filepath)
+ # NB. the parameters below are a bit ad-hoc. After 16 iterations,
+ # the we trace from the "while" and reach a "trace too long". Then
+ # in the next execution, we trace the "rec" function from start;
+ # that's "functrace" below. Then after one or two extra iterations
+ # we try again from "while", and this time we succeed.
+ log = self.run(fn, [], threshold=20)
+ functrace, loop = log.loops_by_filename(self.filepath)
assert loop.match_by_id('call_rec', """
...
p53 = call_assembler(..., descr=...)
diff --git a/pypy/module/pypyjit/test_pypy_c/test_cprofile.py b/pypy/module/pypyjit/test_pypy_c/test_cprofile.py
--- a/pypy/module/pypyjit/test_pypy_c/test_cprofile.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_cprofile.py
@@ -1,4 +1,4 @@
-import py, sys
+import py, sys, re
from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC
class TestCProfile(BaseTestPyPyC):
@@ -26,10 +26,20 @@
for method in ['append', 'pop']:
loop, = log.loops_by_id(method)
print loop.ops_by_id(method)
- # on 32-bit, there is f1=read_timestamp(); ...;
- # f2=read_timestamp(); f3=call(llong_sub,f1,f2)
- # which should turn into a single PADDQ/PSUBQ
- if sys.maxint != 2147483647:
- assert ' call(' not in repr(loop.ops_by_id(method))
+ # on 32-bit, there is f1=call(read_timestamp); ...;
+ # f2=call(read_timestamp); f3=call(llong_sub,f1,f2)
+ # but all calls can be special-cased by the backend if
+ # supported. On 64-bit there is only the two calls to
+ # read_timestamp.
+ r = re.compile(r" call[(]ConstClass[(](.+?)[)]")
+ calls = r.findall(repr(loop.ops_by_id(method)))
+ if sys.maxint == 2147483647:
+ assert len(calls) == 6
+ else:
+ assert len(calls) == 2
+ for x in calls:
+ assert ('ll_read_timestamp' in x or 'llong_sub' in x
+ or 'llong_add' in x)
+ #
assert ' call_may_force(' not in repr(loop.ops_by_id(method))
assert ' cond_call(' in repr(loop.ops_by_id(method))
diff --git a/pypy/module/pypyjit/test_pypy_c/test_ffi.py b/pypy/module/pypyjit/test_pypy_c/test_ffi.py
--- a/pypy/module/pypyjit/test_pypy_c/test_ffi.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_ffi.py
@@ -340,30 +340,19 @@
guard_value(p166, ConstPtr(ptr72), descr=...)
p167 = call(ConstClass(_ll_0_alloc_with_del___), descr=<Callr . EF=4>)
guard_no_exception(descr=...)
- i168 = call(ConstClass(_ll_1_raw_malloc_varsize__Signed), 6, descr=<Calli . i EF=4 OS=110>)
- i169 = int_add(i168, i97)
- i170 = int_sub(i160, i106)
- setfield_gc(p167, i168, descr=<FieldU pypy.module._cffi_backend.cdataobj.W_CData.inst__cdata .>)
+ i112 = int_sub(i160, -32768)
setfield_gc(p167, ConstPtr(null), descr=<FieldP pypy.module._cffi_backend.cdataobj.W_CData.inst__lifeline_ .+>)
- setfield_gc(p167, ConstPtr(ptr89), descr=<FieldP pypy.module._cffi_backend.cdataobj.W_CData.inst_ctype .+>)
- i171 = uint_gt(i170, i108)
- guard_false(i171, descr=...)
- i172 = int_sub(i160, -32768)
- i173 = int_and(i172, 65535)
- i174 = int_add(i173, -32768)
- setarrayitem_raw(i169, 0, i174, descr=<ArrayS 2>)
- i175 = int_add(i168, i121)
- i176 = int_sub(i160, i130)
- i177 = uint_gt(i176, i132)
- guard_false(i177, descr=...)
- setarrayitem_raw(i175, 0, i174, descr=<ArrayS 2>)
- i178 = int_add(i168, i140)
- i179 = int_sub(i160, i149)
- i180 = uint_gt(i179, i151)
- guard_false(i180, descr=...)
- setarrayitem_raw(i178, 0, i174, descr=<ArrayS 2>)
+ setfield_gc(p167, ConstPtr(ptr85), descr=<FieldP pypy.module._cffi_backend.cdataobj.W_CData.inst_ctype .+>)
+ i114 = uint_gt(i112, 65535)
+ guard_false(i114, descr=...)
+ i115 = int_and(i112, 65535)
+ i116 = int_add(i115, -32768)
--TICK--
- i183 = arraylen_gc(p67, descr=<ArrayP .>)
- i184 = arraylen_gc(p92, descr=<ArrayP .>)
+ i119 = call(ConstClass(_ll_1_raw_malloc_varsize__Signed), 6, descr=<Calli . i EF=4 OS=110>)
+ raw_store(i119, 0, i116, descr=<ArrayS 2>)
+ raw_store(i119, 2, i116, descr=<ArrayS 2>)
+ raw_store(i119, 4, i116, descr=<ArrayS 2>)
+ setfield_gc(p167, i119, descr=<FieldU pypy.module._cffi_backend.cdataobj.W_CData.inst__cdata .+>)
+ i123 = arraylen_gc(p67, descr=<ArrayP .>)
jump(..., descr=...)
""")
diff --git a/pypy/module/sys/initpath.py b/pypy/module/sys/initpath.py
--- a/pypy/module/sys/initpath.py
+++ b/pypy/module/sys/initpath.py
@@ -18,6 +18,13 @@
_WIN32 = sys.platform == 'win32'
+def _exists_and_is_executable(fn):
+ # os.access checks using the user's real uid and gid.
+ # Since pypy should not be run setuid/setgid, this
+ # should be sufficient.
+ return os.path.isfile(fn) and os.access(fn, os.X_OK)
+
+
def find_executable(executable):
"""
Return the absolute path of the executable, by looking into PATH and
@@ -34,14 +41,14 @@
if path:
for dir in path.split(os.pathsep):
fn = os.path.join(dir, executable)
- if os.path.isfile(fn):
+ if _exists_and_is_executable(fn):
executable = fn
break
executable = rpath.rabspath(executable)
# 'sys.executable' should not end up being an non-existing file;
# just use '' in this case. (CPython issue #7774)
- return executable if os.path.isfile(executable) else ''
+ return executable if _exists_and_is_executable(executable) else ''
def _readlink_maybe(filename):
diff --git a/pypy/module/sys/state.py b/pypy/module/sys/state.py
--- a/pypy/module/sys/state.py
+++ b/pypy/module/sys/state.py
@@ -7,15 +7,15 @@
# ____________________________________________________________
#
-class State:
- def __init__(self, space):
- self.space = space
+class State:
+ def __init__(self, space):
+ self.space = space
self.w_modules = space.newdict(module=True)
-
self.w_warnoptions = space.newlist([])
self.w_argv = space.newlist([])
- self.setinitialpath(space)
+
+ self.setinitialpath(space)
def setinitialpath(self, space):
from pypy.module.sys.initpath import compute_stdlib_path
@@ -25,10 +25,10 @@
path = compute_stdlib_path(self, srcdir)
self.w_path = space.newlist([space.wrap(p) for p in path])
-
def get(space):
return space.fromcache(State)
+
class IOState:
def __init__(self, space):
from pypy.module._file.interp_file import W_File
@@ -36,17 +36,17 @@
stdin = W_File(space)
stdin.file_fdopen(0, "r", 1)
- stdin.name = '<stdin>'
+ stdin.w_name = space.wrap('<stdin>')
self.w_stdin = space.wrap(stdin)
stdout = W_File(space)
stdout.file_fdopen(1, "w", 1)
- stdout.name = '<stdout>'
+ stdout.w_name = space.wrap('<stdout>')
self.w_stdout = space.wrap(stdout)
stderr = W_File(space)
stderr.file_fdopen(2, "w", 0)
- stderr.name = '<stderr>'
+ stderr.w_name = space.wrap('<stderr>')
self.w_stderr = space.wrap(stderr)
stdin._when_reading_first_flush(stdout)
@@ -54,9 +54,9 @@
def getio(space):
return space.fromcache(IOState)
+
def pypy_getudir(space):
"""NOT_RPYTHON
(should be removed from interpleveldefs before translation)"""
from rpython.tool.udir import udir
return space.wrap(str(udir))
-
diff --git a/pypy/module/sys/test/test_initpath.py b/pypy/module/sys/test/test_initpath.py
--- a/pypy/module/sys/test/test_initpath.py
+++ b/pypy/module/sys/test/test_initpath.py
@@ -57,6 +57,7 @@
a.join('pypy').ensure(file=True)
b.join('pypy').ensure(file=True)
#
+ monkeypatch.setattr(os, 'access', lambda x, y: True)
# if there is already a slash, don't do anything
monkeypatch.chdir(tmpdir)
assert find_executable('a/pypy') == a.join('pypy')
@@ -82,7 +83,11 @@
# if pypy is found but it's not a file, ignore it
c.join('pypy').ensure(dir=True)
assert find_executable('pypy') == a.join('pypy')
+ # if pypy is found but it's not executable, ignore it
+ monkeypatch.setattr(os, 'access', lambda x, y: False)
+ assert find_executable('pypy') == ''
#
+ monkeypatch.setattr(os, 'access', lambda x, y: True)
monkeypatch.setattr(initpath, 'we_are_translated', lambda: True)
monkeypatch.setattr(initpath, '_WIN32', True)
monkeypatch.setenv('PATH', str(a))
diff --git a/pypy/module/sys/test/test_sysmodule.py b/pypy/module/sys/test/test_sysmodule.py
--- a/pypy/module/sys/test/test_sysmodule.py
+++ b/pypy/module/sys/test/test_sysmodule.py
@@ -91,6 +91,10 @@
assert isinstance(sys.__stderr__, file)
assert isinstance(sys.__stdin__, file)
+ #assert sys.__stdin__.name == "<stdin>"
+ #assert sys.__stdout__.name == "<stdout>"
+ #assert sys.__stderr__.name == "<stderr>"
+
if self.appdirect and not isinstance(sys.stdin, file):
return
diff --git a/pypy/module/sys/version.py b/pypy/module/sys/version.py
--- a/pypy/module/sys/version.py
+++ b/pypy/module/sys/version.py
@@ -10,7 +10,7 @@
#XXX # sync CPYTHON_VERSION with patchlevel.h, package.py
CPYTHON_API_VERSION = 1013 #XXX # sync with include/modsupport.h
-PYPY_VERSION = (2, 3, 1, "final", 0) #XXX # sync patchlevel.h
+PYPY_VERSION = (2, 5, 0, "alpha", 0) #XXX # sync patchlevel.h
if platform.name == 'msvc':
COMPILER_INFO = 'MSC v.%d 32 bit' % (platform.version * 10 + 600)
diff --git a/pypy/module/thread/test/test_thread.py b/pypy/module/thread/test/test_thread.py
--- a/pypy/module/thread/test/test_thread.py
+++ b/pypy/module/thread/test/test_thread.py
@@ -13,18 +13,26 @@
def f():
lock.acquire()
lock.release()
+ start = thread._count()
try:
try:
for i in range(1000):
thread.start_new_thread(f, ())
finally:
lock.release()
- # wait a bit to allow most threads to finish now
- time.sleep(0.5)
except (thread.error, MemoryError):
cls.w_can_start_many_threads = space.wrap(False)
else:
cls.w_can_start_many_threads = space.wrap(True)
+ # wait a bit to allow all threads to finish now
+ remaining = thread._count()
+ retries = 0
+ while remaining > start:
+ retries += 1
+ if retries == 200:
+ raise Exception("the test's threads don't stop!")
+ time.sleep(0.2)
+ remaining = thread._count()
def test_start_new_thread(self):
import thread
@@ -227,7 +235,7 @@
import signal
def f():
- for x in range(5):
+ for x in range(40):
if waiting:
thread.interrupt_main()
return
@@ -236,7 +244,7 @@
def busy_wait():
waiting.append(None)
- for x in range(10):
+ for x in range(50):
print 'tick...', x # <-force the GIL to be released, as
time.sleep(0.1) # time.sleep doesn't do non-translated
waiting.pop()
@@ -245,6 +253,8 @@
signal.signal(signal.SIGINT, signal.default_int_handler)
for i in range(100):
+ print
+ print "loop", i
waiting = []
thread.start_new_thread(f, ())
raises(KeyboardInterrupt, busy_wait)
diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py
--- a/pypy/objspace/descroperation.py
+++ b/pypy/objspace/descroperation.py
@@ -671,6 +671,7 @@
left, right = specialnames
errormsg = "unsupported operand type(s) for %s: '%%N' and '%%N'" % (
symbol.replace('%', '%%'),)
+ seq_bug_compat = (symbol == '+' or symbol == '*')
def binop_impl(space, w_obj1, w_obj2):
w_typ1 = space.type(w_obj1)
@@ -686,20 +687,16 @@
# __xxx__ and __rxxx__ methods where found by identity.
# Note that space.is_w() is potentially not happy if one of them
# is None...
- if w_left_src is not w_right_src: # XXX
- # -- cpython bug compatibility: see objspace/std/test/
- # -- test_unicodeobject.test_str_unicode_concat_overrides.
- # -- The following handles "unicode + string subclass" by
- # -- pretending that the unicode is a superclass of the
- # -- string, thus giving priority to the string subclass'
- # -- __radd__() method. The case "string + unicode subclass"
- # -- is handled directly by add__String_Unicode().
- if symbol == '+' and space.is_w(w_typ1, space.w_unicode):
- w_typ1 = space.w_basestring
- # -- end of bug compatibility
- if space.is_true(space.issubtype(w_typ2, w_typ1)):
- if (w_left_src and w_right_src and
- not space.abstract_issubclass_w(w_left_src, w_right_src) and
+ if w_right_src and (w_left_src is not w_right_src) and w_left_src:
+ # 'seq_bug_compat' is for cpython bug-to-bug compatibility:
+ # see objspace/std/test/test_unicodeobject.*concat_overrides
+ # and objspace/test/test_descrobject.*rmul_overrides.
+ # For cases like "unicode + string subclass".
+ if ((seq_bug_compat and w_typ1.flag_sequence_bug_compat
+ and not w_typ2.flag_sequence_bug_compat)
+ # the non-bug-compat part is the following check:
+ or space.is_true(space.issubtype(w_typ2, w_typ1))):
+ if (not space.abstract_issubclass_w(w_left_src, w_right_src) and
not space.abstract_issubclass_w(w_typ1, w_right_src)):
w_obj1, w_obj2 = w_obj2, w_obj1
w_left_impl, w_right_impl = w_right_impl, w_left_impl
diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py
--- a/pypy/objspace/std/bytearrayobject.py
+++ b/pypy/objspace/std/bytearrayobject.py
@@ -534,7 +534,7 @@
if not e.match(space, space.w_TypeError):
raise
else:
- return [c for c in buf.as_str()]
+ return list(buf.as_str())
# sequence of bytes
w_iter = space.iter(w_source)
@@ -1131,6 +1131,7 @@
reverse = interp2app(W_BytearrayObject.descr_reverse,
doc=BytearrayDocstrings.reverse.__doc__),
)
+W_BytearrayObject.typedef.flag_sequence_bug_compat = True
init_signature = Signature(['source', 'encoding', 'errors'], None, None)
init_defaults = [None, None, None]
diff --git a/pypy/objspace/std/bytesobject.py b/pypy/objspace/std/bytesobject.py
--- a/pypy/objspace/std/bytesobject.py
+++ b/pypy/objspace/std/bytesobject.py
@@ -951,6 +951,7 @@
_formatter_field_name_split =
interp2app(W_BytesObject.descr_formatter_field_name_split),
)
+W_BytesObject.typedef.flag_sequence_bug_compat = True
def string_escape_encode(s, quote):
diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py
--- a/pypy/objspace/std/listobject.py
+++ b/pypy/objspace/std/listobject.py
@@ -1874,3 +1874,4 @@
insert = interp2app(W_ListObject.descr_insert),
remove = interp2app(W_ListObject.descr_remove),
)
+W_ListObject.typedef.flag_sequence_bug_compat = True
diff --git a/pypy/objspace/std/stdtypedef.py b/pypy/objspace/std/stdtypedef.py
--- a/pypy/objspace/std/stdtypedef.py
+++ b/pypy/objspace/std/stdtypedef.py
@@ -93,6 +93,8 @@
overridetypedef=overridetypedef)
if typedef is not overridetypedef:
w_type.w_doc = space.wrap(typedef.doc)
+ if hasattr(typedef, 'flag_sequence_bug_compat'):
+ w_type.flag_sequence_bug_compat = typedef.flag_sequence_bug_compat
w_type.lazyloaders = lazyloaders
return w_type
diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py
--- a/pypy/objspace/std/tupleobject.py
+++ b/pypy/objspace/std/tupleobject.py
@@ -244,6 +244,7 @@
count = interp2app(W_AbstractTupleObject.descr_count),
index = interp2app(W_AbstractTupleObject.descr_index)
)
+W_AbstractTupleObject.typedef.flag_sequence_bug_compat = True
class W_TupleObject(W_AbstractTupleObject):
diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py
--- a/pypy/objspace/std/typeobject.py
+++ b/pypy/objspace/std/typeobject.py
@@ -67,6 +67,7 @@
_immutable_fields_ = ["flag_heaptype",
"flag_cpytype",
"flag_abstract?",
+ "flag_sequence_bug_compat",
'needsdel',
'weakrefable',
'hasdict',
@@ -104,6 +105,7 @@
w_self.flag_heaptype = False
w_self.flag_cpytype = False
w_self.flag_abstract = False
+ w_self.flag_sequence_bug_compat = False
w_self.instancetypedef = overridetypedef
if overridetypedef is not None:
diff --git a/pypy/objspace/std/unicodeobject.py b/pypy/objspace/std/unicodeobject.py
--- a/pypy/objspace/std/unicodeobject.py
+++ b/pypy/objspace/std/unicodeobject.py
@@ -1068,6 +1068,7 @@
_formatter_field_name_split =
interp2app(W_UnicodeObject.descr_formatter_field_name_split),
)
+W_UnicodeObject.typedef.flag_sequence_bug_compat = True
def _create_list_from_unicode(value):
diff --git a/pypy/objspace/test/test_descroperation.py b/pypy/objspace/test/test_descroperation.py
--- a/pypy/objspace/test/test_descroperation.py
+++ b/pypy/objspace/test/test_descroperation.py
@@ -734,6 +734,44 @@
assert X() == 'hello'
+ def test_sequence_rmul_overrides(self):
+ class oops(object):
+ def __rmul__(self, other):
+ return 42
+ def __index__(self):
+ return 3
+ assert '2' * oops() == 42
+ assert [2] * oops() == 42
+ assert (2,) * oops() == 42
+ assert u'2' * oops() == 42
+ assert bytearray('2') * oops() == 42
+ assert 1000 * oops() == 42
+ assert '2'.__mul__(oops()) == '222'
+
+ def test_sequence_rmul_overrides_oldstyle(self):
+ class oops:
+ def __rmul__(self, other):
+ return 42
+ def __index__(self):
+ return 3
+ assert '2' * oops() == 42
+ assert [2] * oops() == 42
+ assert (2,) * oops() == 42
+ assert u'2' * oops() == 42
+ assert bytearray('2') * oops() == 42
+ assert 1000 * oops() == 42
+ assert '2'.__mul__(oops()) == '222'
+
+ def test_sequence_radd_overrides(self):
+ class A1(list):
+ pass
+ class A2(list):
+ def __radd__(self, other):
+ return 42
+ assert [2] + A1([3]) == [2, 3]
+ assert type([2] + A1([3])) is list
+ assert [2] + A2([3]) == 42
+
class AppTestWithBuiltinShortcut(AppTest_Descroperation):
spaceconfig = {'objspace.std.builtinshortcut': True}
diff --git a/pypy/tool/release/package.py b/pypy/tool/release/package.py
--- a/pypy/tool/release/package.py
+++ b/pypy/tool/release/package.py
@@ -297,7 +297,13 @@
argparse = imp.load_source('argparse', 'lib-python/2.7/argparse.py')
if sys.platform == 'win32':
pypy_exe = 'pypy.exe'
More information about the pypy-commit
mailing list