[pypy-commit] pypy default: merge
fijal
noreply at buildbot.pypy.org
Fri Jan 31 13:59:29 CET 2014
Author: Maciej Fijalkowski <fijall at gmail.com>
Branch:
Changeset: r69036:22ee335c3d51
Date: 2014-01-31 13:58 +0100
http://bitbucket.org/pypy/pypy/changeset/22ee335c3d51/
Log: merge
diff --git a/pypy/module/_cffi_backend/handle.py b/pypy/module/_cffi_backend/handle.py
--- a/pypy/module/_cffi_backend/handle.py
+++ b/pypy/module/_cffi_backend/handle.py
@@ -2,58 +2,13 @@
from pypy.interpreter.error import OperationError, operationerrfmt
from pypy.interpreter.gateway import unwrap_spec
from pypy.module._cffi_backend import ctypeobj, ctypeptr, cdataobj
-from pypy.module._weakref.interp__weakref import dead_ref
from rpython.rtyper.lltypesystem import lltype, rffi
+from rpython.rlib import rweaklist
-def reduced_value(s):
- while True:
- divide = s & 1
- s >>= 1
- if not divide:
- return s
-
-# ____________________________________________________________
-
-
-class CffiHandles:
+class CffiHandles(rweaklist.RWeakListMixin):
def __init__(self, space):
- self.handles = []
- self.look_distance = 0
-
- def reserve_next_handle_index(self):
- # The reservation ordering done here is tweaked for pypy's
- # memory allocator. We look from index 'look_distance'.
- # Look_distance increases from 0. But we also look at
- # "look_distance/2" or "/4" or "/8", etc. If we find that one
- # of these secondary locations is free, we assume it's because
- # there was recently a minor collection; so we reset
- # look_distance to 0 and start again from the lowest locations.
- length = len(self.handles)
- for d in range(self.look_distance, length):
- if self.handles[d]() is None:
- self.look_distance = d + 1
- return d
- s = reduced_value(d)
- if self.handles[s]() is None:
- break
- # restart from the beginning
- for d in range(0, length):
- if self.handles[d]() is None:
- self.look_distance = d + 1
- return d
- # full! extend, but don't use '+=' here
- self.handles = self.handles + [dead_ref] * (length // 3 + 5)
- self.look_distance = length + 1
- return length
-
- def store_handle(self, index, content):
- self.handles[index] = weakref.ref(content)
-
- def fetch_handle(self, index):
- if 0 <= index < len(self.handles):
- return self.handles[index]()
- return None
+ self.initialize()
def get(space):
return space.fromcache(CffiHandles)
diff --git a/pypy/module/_io/interp_iobase.py b/pypy/module/_io/interp_iobase.py
--- a/pypy/module/_io/interp_iobase.py
+++ b/pypy/module/_io/interp_iobase.py
@@ -5,7 +5,7 @@
from pypy.interpreter.gateway import interp2app
from pypy.interpreter.error import OperationError, operationerrfmt
from rpython.rlib.rstring import StringBuilder
-from rpython.rlib import rweakref
+from rpython.rlib import rweakref, rweaklist
DEFAULT_BUFFER_SIZE = 8192
@@ -52,7 +52,6 @@
self.w_dict = space.newdict()
self.__IOBase_closed = False
if add_to_autoflusher:
- self.streamholder = None # needed by AutoFlusher
get_autoflusher(space).add(self)
def getdict(self, space):
@@ -115,7 +114,6 @@
space.call_method(self, "flush")
finally:
self.__IOBase_closed = True
- get_autoflusher(space).remove(self)
def flush_w(self, space):
if self._CLOSED():
@@ -339,55 +337,35 @@
# functions to make sure that all streams are flushed on exit
# ------------------------------------------------------------
-class StreamHolder(object):
- def __init__(self, w_iobase):
- self.w_iobase_ref = rweakref.ref(w_iobase)
- w_iobase.autoflusher = self
- def autoflush(self, space):
- w_iobase = self.w_iobase_ref()
- if w_iobase is not None:
- try:
- space.call_method(w_iobase, 'flush')
- except OperationError:
- # Silencing all errors is bad, but getting randomly
- # interrupted here is equally as bad, and potentially
- # more frequent (because of shutdown issues).
- pass
-
-
-class AutoFlusher(object):
+class AutoFlusher(rweaklist.RWeakListMixin):
def __init__(self, space):
- self.streams = {}
+ self.initialize()
def add(self, w_iobase):
- assert w_iobase.streamholder is None
if rweakref.has_weakref_support():
- holder = StreamHolder(w_iobase)
- w_iobase.streamholder = holder
- self.streams[holder] = None
+ self.add_handle(w_iobase)
#else:
# no support for weakrefs, so ignore and we
# will not get autoflushing
- def remove(self, w_iobase):
- holder = w_iobase.streamholder
- if holder is not None:
- try:
- del self.streams[holder]
- except KeyError:
- # this can happen in daemon threads
- pass
-
def flush_all(self, space):
- while self.streams:
- for streamholder in self.streams.keys():
+ while True:
+ handles = self.get_all_handles()
+ if len(handles) == 0:
+ break
+ self.initialize() # reset the state here
+ for wr in handles:
+ w_iobase = wr()
+ if w_iobase is None:
+ continue
try:
- del self.streams[streamholder]
- except KeyError:
- pass # key was removed in the meantime
- else:
- streamholder.autoflush(space)
+ space.call_method(w_iobase, 'flush')
+ except OperationError:
+ # Silencing all errors is bad, but getting randomly
+ # interrupted here is equally as bad, and potentially
+ # more frequent (because of shutdown issues).
+ pass
def get_autoflusher(space):
return space.fromcache(AutoFlusher)
diff --git a/pypy/module/_weakref/interp__weakref.py b/pypy/module/_weakref/interp__weakref.py
--- a/pypy/module/_weakref/interp__weakref.py
+++ b/pypy/module/_weakref/interp__weakref.py
@@ -6,6 +6,7 @@
from rpython.rlib import jit
from rpython.rlib.rshrinklist import AbstractShrinkList
from rpython.rlib.objectmodel import specialize
+from rpython.rlib.rweakref import dead_ref
import weakref
@@ -144,14 +145,6 @@
# ____________________________________________________________
-class Dummy:
- pass
-dead_ref = weakref.ref(Dummy())
-for i in range(5):
- if dead_ref() is not None:
- import gc; gc.collect()
-assert dead_ref() is None
-
class W_WeakrefBase(W_Root):
def __init__(w_self, space, w_obj, w_callable):
diff --git a/pypy/module/exceptions/interp_exceptions.py b/pypy/module/exceptions/interp_exceptions.py
--- a/pypy/module/exceptions/interp_exceptions.py
+++ b/pypy/module/exceptions/interp_exceptions.py
@@ -446,6 +446,9 @@
if hasattr(rwin32, 'build_winerror_to_errno'):
_winerror_to_errno, _default_errno = rwin32.build_winerror_to_errno()
+ # Python 2 doesn't map ERROR_DIRECTORY (267) to ENOTDIR but
+ # Python 3 (CPython issue #12802) and build_winerror_to_errno do
+ del _winerror_to_errno[267]
else:
_winerror_to_errno, _default_errno = {}, 22 # EINVAL
diff --git a/pypy/module/micronumpy/interp_boxes.py b/pypy/module/micronumpy/interp_boxes.py
--- a/pypy/module/micronumpy/interp_boxes.py
+++ b/pypy/module/micronumpy/interp_boxes.py
@@ -256,6 +256,10 @@
value = space.is_true(self)
return get_dtype_cache(space).w_booldtype.box(value)
+ def descr_zero(self, space):
+ from pypy.module.micronumpy.interp_dtype import get_dtype_cache
+ return get_dtype_cache(space).w_longdtype.box(0)
+
def descr_ravel(self, space):
from pypy.module.micronumpy.base import convert_to_array
w_values = space.newtuple([self])
@@ -327,6 +331,9 @@
def descr_buffer(self, space):
return self.descr_ravel(space).descr_get_data(space)
+ def descr_byteswap(self, space):
+ return self.get_dtype(space).itemtype.byteswap(self)
+
w_flags = None
def descr_get_flags(self, space):
if self.w_flags is None:
@@ -583,6 +590,12 @@
__hash__ = interp2app(W_GenericBox.descr_hash),
tolist = interp2app(W_GenericBox.item),
+ min = interp2app(W_GenericBox.descr_self),
+ max = interp2app(W_GenericBox.descr_self),
+ argmin = interp2app(W_GenericBox.descr_zero),
+ argmax = interp2app(W_GenericBox.descr_zero),
+ sum = interp2app(W_GenericBox.descr_self),
+ prod = interp2app(W_GenericBox.descr_self),
any = interp2app(W_GenericBox.descr_any),
all = interp2app(W_GenericBox.descr_all),
ravel = interp2app(W_GenericBox.descr_ravel),
@@ -592,6 +605,7 @@
view = interp2app(W_GenericBox.descr_view),
squeeze = interp2app(W_GenericBox.descr_self),
copy = interp2app(W_GenericBox.descr_copy),
+ byteswap = interp2app(W_GenericBox.descr_byteswap),
dtype = GetSetProperty(W_GenericBox.descr_get_dtype),
size = GetSetProperty(W_GenericBox.descr_get_size),
diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py
--- a/pypy/module/micronumpy/interp_dtype.py
+++ b/pypy/module/micronumpy/interp_dtype.py
@@ -803,29 +803,19 @@
for dtype in reversed(self.builtin_dtypes):
self.dtypes_by_num[dtype.num] = dtype
self.dtypes_by_name[dtype.name] = dtype
- can_name = dtype.kind + str(dtype.get_size())
- self.dtypes_by_name[can_name] = dtype
- self.dtypes_by_name[NPY_NATBYTE + can_name] = dtype
- self.dtypes_by_name[NPY_NATIVE + can_name] = dtype
- new_name = NPY_OPPBYTE + can_name
- itemtype = type(dtype.itemtype)(False)
- self.dtypes_by_name[new_name] = W_Dtype(
- itemtype, dtype.num, dtype.kind, new_name, dtype.char,
- dtype.w_box_type, byteorder=NPY_OPPBYTE,
- float_type=dtype.float_type)
- if dtype.kind != dtype.char:
- can_name = dtype.char
+ for can_name in [dtype.kind + str(dtype.get_size()),
+ dtype.char]:
+ self.dtypes_by_name[can_name] = dtype
self.dtypes_by_name[NPY_NATBYTE + can_name] = dtype
self.dtypes_by_name[NPY_NATIVE + can_name] = dtype
new_name = NPY_OPPBYTE + can_name
+ itemtype = type(dtype.itemtype)(False)
self.dtypes_by_name[new_name] = W_Dtype(
itemtype, dtype.num, dtype.kind, new_name, dtype.char,
dtype.w_box_type, byteorder=NPY_OPPBYTE,
float_type=dtype.float_type)
-
for alias in dtype.aliases:
self.dtypes_by_name[alias] = dtype
- self.dtypes_by_name[dtype.char] = dtype
typeinfo_full = {
'LONGLONG': self.w_int64dtype,
diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py
--- a/pypy/module/micronumpy/test/test_dtypes.py
+++ b/pypy/module/micronumpy/test/test_dtypes.py
@@ -788,6 +788,14 @@
assert dtype('>i8').str == '>i8'
assert dtype('int8').str == '|i1'
assert dtype('float').str == byteorder + 'f8'
+ assert dtype('f').str == byteorder + 'f4'
+ assert dtype('=f').str == byteorder + 'f4'
+ assert dtype('>f').str == '>f4'
+ assert dtype('<f').str == '<f4'
+ assert dtype('d').str == byteorder + 'f8'
+ assert dtype('=d').str == byteorder + 'f8'
+ assert dtype('>d').str == '>f8'
+ assert dtype('<d').str == '<f8'
# strange
assert dtype('string').str == '|S0'
assert dtype('unicode').str == byteorder + 'U0'
diff --git a/pypy/module/micronumpy/test/test_scalar.py b/pypy/module/micronumpy/test/test_scalar.py
--- a/pypy/module/micronumpy/test/test_scalar.py
+++ b/pypy/module/micronumpy/test/test_scalar.py
@@ -102,6 +102,16 @@
assert b == a
assert b is not a
+ def test_methods(self):
+ import numpy as np
+ for a in [np.int32(2), np.float64(2.0), np.complex64(42)]:
+ for op in ['min', 'max', 'sum', 'prod']:
+ assert getattr(a, op)() == a
+ for op in ['argmin', 'argmax']:
+ b = getattr(a, op)()
+ assert type(b) is np.int_
+ assert b == 0
+
def test_buffer(self):
import numpy as np
a = np.int32(123)
@@ -111,6 +121,13 @@
b = buffer(a)
assert str(b) == a
+ def test_byteswap(self):
+ import numpy as np
+ assert np.int64(123).byteswap() == 8863084066665136128
+ a = np.complex64(1+2j).byteswap()
+ assert repr(a.real).startswith('4.60060')
+ assert repr(a.imag).startswith('8.96831')
+
def test_squeeze(self):
import numpy as np
assert np.True_.squeeze() is np.True_
diff --git a/rpython/rlib/rbigint.py b/rpython/rlib/rbigint.py
--- a/rpython/rlib/rbigint.py
+++ b/rpython/rlib/rbigint.py
@@ -254,16 +254,18 @@
@staticmethod
@jit.elidable
- def fromstr(s, base=0):
- """As string_to_int(), but ignores an optional 'l' or 'L' suffix
- and returns an rbigint."""
+ def fromstr(s, base=0, ignore_l_suffix=False, fname='long'):
+ """As string_to_int(), but optionally ignores an optional 'l' or
+ 'L' suffix and returns an rbigint.
+ """
from rpython.rlib.rstring import NumberStringParser, \
strip_spaces
s = literal = strip_spaces(s)
- if (s.endswith('l') or s.endswith('L')) and base < 22:
+ if (not ignore_l_suffix and (s.endswith('l') or s.endswith('L')) and
+ base < 22):
# in base 22 and above, 'L' is a valid digit! try: long('L',22)
s = s[:-1]
- parser = NumberStringParser(s, literal, base, 'long')
+ parser = NumberStringParser(s, literal, base, fname)
return rbigint._from_numberstring_parser(parser)
@staticmethod
diff --git a/rpython/rlib/rweaklist.py b/rpython/rlib/rweaklist.py
new file mode 100644
--- /dev/null
+++ b/rpython/rlib/rweaklist.py
@@ -0,0 +1,60 @@
+import weakref
+from rpython.rlib.rweakref import dead_ref
+
+
+def _reduced_value(s):
+ while True:
+ divide = s & 1
+ s >>= 1
+ if not divide:
+ return s
+
+
+class RWeakListMixin(object):
+ _mixin_ = True
+
+ def initialize(self):
+ self.handles = []
+ self.look_distance = 0
+
+ def get_all_handles(self):
+ return self.handles
+
+ def reserve_next_handle_index(self):
+ # The reservation ordering done here is tweaked for pypy's
+ # memory allocator. We look from index 'look_distance'.
+ # Look_distance increases from 0. But we also look at
+ # "look_distance/2" or "/4" or "/8", etc. If we find that one
+ # of these secondary locations is free, we assume it's because
+ # there was recently a minor collection; so we reset
+ # look_distance to 0 and start again from the lowest locations.
+ length = len(self.handles)
+ for d in range(self.look_distance, length):
+ if self.handles[d]() is None:
+ self.look_distance = d + 1
+ return d
+ s = _reduced_value(d)
+ if self.handles[s]() is None:
+ break
+ # restart from the beginning
+ for d in range(0, length):
+ if self.handles[d]() is None:
+ self.look_distance = d + 1
+ return d
+ # full! extend, but don't use '+=' here
+ self.handles = self.handles + [dead_ref] * (length // 3 + 5)
+ self.look_distance = length + 1
+ return length
+
+ def add_handle(self, content):
+ index = self.reserve_next_handle_index()
+ self.store_handle(index, content)
+ return index
+
+ def store_handle(self, index, content):
+ self.handles[index] = weakref.ref(content)
+
+ def fetch_handle(self, index):
+ if 0 <= index < len(self.handles):
+ return self.handles[index]()
+ return None
diff --git a/rpython/rlib/rweakref.py b/rpython/rlib/rweakref.py
--- a/rpython/rlib/rweakref.py
+++ b/rpython/rlib/rweakref.py
@@ -12,6 +12,14 @@
def has_weakref_support():
return True # returns False if --no-translation-rweakref
+class Dummy:
+ pass
+dead_ref = weakref.ref(Dummy())
+for i in range(5):
+ if dead_ref() is not None:
+ import gc; gc.collect()
+assert dead_ref() is None # a known-to-be-dead weakref object
+
class RWeakValueDictionary(object):
"""A dictionary containing weak values."""
diff --git a/rpython/rlib/rwin32.py b/rpython/rlib/rwin32.py
--- a/rpython/rlib/rwin32.py
+++ b/rpython/rlib/rwin32.py
@@ -178,8 +178,13 @@
int i;
for(i=1; i < 65000; i++) {
_dosmaperr(i);
- if (errno == EINVAL)
- continue;
+ if (errno == EINVAL) {
+ /* CPython issue #12802 */
+ if (i == ERROR_DIRECTORY)
+ errno = ENOTDIR;
+ else
+ continue;
+ }
printf("%d\t%d\n", i, errno);
}
return 0;
@@ -201,7 +206,7 @@
132: 13, 145: 41, 158: 13, 161: 2, 164: 11, 167: 13, 183: 17,
188: 8, 189: 8, 190: 8, 191: 8, 192: 8, 193: 8, 194: 8,
195: 8, 196: 8, 197: 8, 198: 8, 199: 8, 200: 8, 201: 8,
- 202: 8, 206: 2, 215: 11, 1816: 12,
+ 202: 8, 206: 2, 215: 11, 267: 20, 1816: 12,
}
else:
output = os.popen(str(exename))
diff --git a/rpython/rlib/test/test_rbigint.py b/rpython/rlib/test/test_rbigint.py
--- a/rpython/rlib/test/test_rbigint.py
+++ b/rpython/rlib/test/test_rbigint.py
@@ -214,8 +214,13 @@
from rpython.rlib.rstring import ParseStringError
assert rbigint.fromstr('123L').tolong() == 123
assert rbigint.fromstr('123L ').tolong() == 123
+ py.test.raises(ParseStringError, rbigint.fromstr, '123L ',
+ ignore_l_suffix=True)
py.test.raises(ParseStringError, rbigint.fromstr, 'L')
py.test.raises(ParseStringError, rbigint.fromstr, 'L ')
+ e = py.test.raises(ParseStringError, rbigint.fromstr, 'L ',
+ fname='int')
+ assert 'int()' in e.value.msg
assert rbigint.fromstr('123L', 4).tolong() == 27
assert rbigint.fromstr('123L', 30).tolong() == 27000 + 1800 + 90 + 21
assert rbigint.fromstr('123L', 22).tolong() == 10648 + 968 + 66 + 21
diff --git a/rpython/rlib/test/test_rweaklist.py b/rpython/rlib/test/test_rweaklist.py
new file mode 100644
--- /dev/null
+++ b/rpython/rlib/test/test_rweaklist.py
@@ -0,0 +1,57 @@
+import gc
+from rpython.rlib.rweaklist import RWeakListMixin
+
+
+class A(object):
+ pass
+
+
+def test_simple():
+ a1 = A(); a2 = A()
+ wlist = RWeakListMixin(); wlist.initialize()
+ i = wlist.add_handle(a1)
+ assert i == 0
+ i = wlist.reserve_next_handle_index()
+ assert i == 1
+ wlist.store_handle(i, a2)
+ assert wlist.fetch_handle(0) is a1
+ assert wlist.fetch_handle(1) is a2
+ #
+ del a2
+ for i in range(5):
+ gc.collect()
+ if wlist.fetch_handle(1) is None:
+ break
+ else:
+ raise AssertionError("handle(1) did not disappear")
+ assert wlist.fetch_handle(0) is a1
+
+def test_reuse():
+ alist = [A() for i in range(200)]
+ wlist = RWeakListMixin(); wlist.initialize()
+ for i in range(200):
+ j = wlist.reserve_next_handle_index()
+ assert j == i
+ wlist.store_handle(i, alist[i])
+ #
+ del alist[1::2]
+ del alist[1::2]
+ del alist[1::2]
+ del alist[1::2]
+ del alist[1::2]
+ for i in range(5):
+ gc.collect()
+ #
+ for i in range(200):
+ a = wlist.fetch_handle(i)
+ if i % 32 == 0:
+ assert a is alist[i // 32]
+ else:
+ assert a is None
+ #
+ maximum = -1
+ for i in range(200):
+ j = wlist.reserve_next_handle_index()
+ maximum = max(maximum, j)
+ wlist.store_handle(j, A())
+ assert maximum <= 240
More information about the pypy-commit
mailing list