[pypy-commit] cffi sirtom67/float_complex: float complex progress. Added __complex__ method to cdata.

2017-02-05 Thread sirtom67
Author: Tom Krauss 
Branch: sirtom67/float_complex
Changeset: r2879:6dcf51c6003c
Date: 2017-02-05 17:13 -0600
http://bitbucket.org/cffi/cffi/changeset/6dcf51c6003c/

Log:float complex progress. Added __complex__ method to cdata. Test
currently failing at > assert repr(complex(cast(p, -0j))) == '-0j' E
assert '0j' == '-0j' E - 0j E + -0j E ? +

diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -884,6 +884,26 @@
 return 0;
 }
 
+static Py_complex
+read_raw_complex_data(char *target, int size)
+{
+Py_complex r = {.real=0, .imag=0};
+if (size == 2*sizeof(float)) {
+float real_part, imag_part;
+memcpy(_part, target + 0, sizeof(float));
+memcpy(_part, target + sizeof(float), sizeof(float));
+r.real = real_part;
+r.imag = imag_part;
+return r;
+}
+if (size == 2*sizeof(double)) {
+memcpy(&(r.real), target, 2*sizeof(double));
+return r;
+}
+Py_FatalError("read_raw_complex_data: bad float size");
+return r;
+}
+
 static void
 write_raw_float_data(char *target, double source, int size)
 {
@@ -1011,6 +1031,10 @@
 return (PyObject *)cd;
 }
 }
+else if (ct->ct_flags & CT_PRIMITIVE_COMPLEX) {
+Py_complex value = read_raw_complex_data(data, ct->ct_size);
+return PyComplex_FromCComplex(value);
+}
 else if (ct->ct_flags & CT_PRIMITIVE_CHAR) {
 /*READ(data, ct->ct_size)*/
 if (ct->ct_size == sizeof(char))
@@ -2009,6 +2033,10 @@
 }
 return PyFloat_FromDouble(value);
 }
+if (cd->c_type->ct_flags & CT_PRIMITIVE_COMPLEX) {
+double value = read_raw_float_data(cd->c_data, cd->c_type->ct_size);
+return PyComplex_FromDoubles(value, 0.0);
+}
 PyErr_Format(PyExc_TypeError, "float() not supported on cdata '%s'",
  cd->c_type->ct_name);
 return NULL;
@@ -2808,6 +2836,19 @@
 }
 }
 
+static PyObject *cdata_complex(PyObject *cd_, PyObject *noarg)
+{
+CDataObject *cd = (CDataObject *)cd_;
+
+if (cd->c_type->ct_flags & CT_PRIMITIVE_COMPLEX) {
+Py_complex value = read_raw_complex_data(cd->c_data, 
cd->c_type->ct_size);
+return PyComplex_FromCComplex(value);
+}
+PyErr_Format(PyExc_TypeError, "complex() not supported on cdata '%s'",
+ cd->c_type->ct_name);
+return NULL;
+}
+
 static PyObject *cdata_iter(CDataObject *);
 
 static PyNumberMethods CData_as_number = {
@@ -2857,8 +2898,9 @@
 };
 
 static PyMethodDef cdata_methods[] = {
-{"__dir__",   cdata_dir,  METH_NOARGS},
-{NULL,NULL}   /* sentinel */
+{"__dir__", cdata_dir,  METH_NOARGS},
+{"__complex__", cdata_complex,  METH_NOARGS},
+{NULL,  NULL}   /* sentinel */
 };
 
 static PyTypeObject CData_Type = {
@@ -3599,7 +3641,6 @@
 /* cast to a complex */
 Py_complex value;
 PyObject *io;
-printf("_cffi_backend.c do_cast  ct->ct_size=%ld\n", ct->ct_size);
 if (CData_Check(ob)) {
 CDataObject *cdsrc = (CDataObject *)ob;
 
@@ -3983,8 +4024,6 @@
 int name_size;
 ffi_type *ffitype;
 
-printf("hello\n");
-
 for (ptypes=types; ; ptypes++) {
 if (ptypes->name == NULL) {
 #ifndef HAVE_WCHAR_H
diff --git a/c/realize_c_type.c b/c/realize_c_type.c
--- a/c/realize_c_type.c
+++ b/c/realize_c_type.c
@@ -101,7 +101,6 @@
 
 static PyObject *build_primitive_type(int num)
 {
-fprintf(stderr, "fonum=%d\n",num);
 /* XXX too many translations between here and new_primitive_type() */
 static const char *primitive_name[] = {
 NULL,
diff --git a/c/test_c.py b/c/test_c.py
--- a/c/test_c.py
+++ b/c/test_c.py
@@ -197,12 +197,12 @@
 py.test.raises(TypeError, float, cast(p, -150))
 assert complex(cast(p, 1.25)) == 1.25
 assert complex(cast(p, 1.25j)) == 1.25j
-assert float(cast(p, INF*1j)) == INF*1j
-assert float(cast(p, -INF)) == -INF
+assert complex(cast(p, complex(0,INF))) == complex(0,INF)
+assert complex(cast(p, -INF)) == -INF
 if name == "float":
 assert complex(cast(p, 1.1j)) != 1.1j # rounding error
 assert complex(cast(p, 1E200+3j)) == INF+3j   # limited range
-assert complex(cast(p, 3+1E200j)) == 3+INF*1j # limited range
+assert complex(cast(p, complex(3,1E200))) == complex(3,INF) # 
limited range
 
 assert cast(p, -1.1j) != cast(p, -1.1j)
 assert repr(complex(cast(p, -0.0)).real) == '-0.0'
___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit


[pypy-commit] pypy py3.5: hg merge vendor/stdlib-3.5: upgrade stdlib to 3.5.3

2017-02-05 Thread arigo
Author: Armin Rigo 
Branch: py3.5
Changeset: r89962:08ae26119b9a
Date: 2017-02-05 22:45 +0100
http://bitbucket.org/pypy/pypy/changeset/08ae26119b9a/

Log:hg merge vendor/stdlib-3.5: upgrade stdlib to 3.5.3

diff too long, truncating to 2000 out of 24845 lines

diff --git a/lib-python/3/_collections_abc.py b/lib-python/3/_collections_abc.py
--- a/lib-python/3/_collections_abc.py
+++ b/lib-python/3/_collections_abc.py
@@ -29,8 +29,8 @@
 # so that they will pass tests like:
 #   it = iter(somebytearray)
 #   assert isinstance(it, Iterable)
-# Note:  in other implementations, these types many not be distinct
-# and they make have their own implementation specific types that
+# Note:  in other implementations, these types might not be distinct
+# and they may have their own implementation specific types that
 # are not included on this list.
 bytes_iterator = type(iter(b''))
 bytearray_iterator = type(iter(bytearray()))
@@ -41,6 +41,7 @@
 list_iterator = type(iter([]))
 list_reverseiterator = type(iter(reversed([])))
 range_iterator = type(iter(range(0)))
+longrange_iterator = type(iter(range(1 << 1000)))
 set_iterator = type(iter(set()))
 str_iterator = type(iter(""))
 tuple_iterator = type(iter(()))
@@ -234,6 +235,7 @@
 Iterator.register(list_iterator)
 Iterator.register(list_reverseiterator)
 Iterator.register(range_iterator)
+Iterator.register(longrange_iterator)
 Iterator.register(set_iterator)
 Iterator.register(str_iterator)
 Iterator.register(tuple_iterator)
diff --git a/lib-python/3/_pydecimal.py b/lib-python/3/_pydecimal.py
--- a/lib-python/3/_pydecimal.py
+++ b/lib-python/3/_pydecimal.py
@@ -1068,12 +1068,11 @@
 return sign + intpart + fracpart + exp
 
 def to_eng_string(self, context=None):
-"""Convert to engineering-type string.
-
-Engineering notation has an exponent which is a multiple of 3, so there
-are up to 3 digits left of the decimal place.
-
-Same rules for when in exponential and when as a value as in __str__.
+"""Convert to a string, using engineering notation if an exponent is 
needed.
+
+Engineering notation has an exponent which is a multiple of 3.  This
+can leave up to 3 digits to the left of the decimal place and may
+require the addition of either one or two trailing zeros.
 """
 return self.__str__(eng=True, context=context)
 
@@ -4107,7 +4106,7 @@
 >>> context.create_decimal_from_float(3.1415926535897932)
 Traceback (most recent call last):
 ...
-decimal.Inexact
+decimal.Inexact: None
 
 """
 d = Decimal.from_float(f)   # An exact conversion
@@ -5502,9 +5501,29 @@
 return r
 
 def to_eng_string(self, a):
-"""Converts a number to a string, using scientific notation.
+"""Convert to a string, using engineering notation if an exponent is 
needed.
+
+Engineering notation has an exponent which is a multiple of 3.  This
+can leave up to 3 digits to the left of the decimal place and may
+require the addition of either one or two trailing zeros.
 
 The operation is not affected by the context.
+
+>>> ExtendedContext.to_eng_string(Decimal('123E+1'))
+'1.23E+3'
+>>> ExtendedContext.to_eng_string(Decimal('123E+3'))
+'123E+3'
+>>> ExtendedContext.to_eng_string(Decimal('123E-10'))
+'12.3E-9'
+>>> ExtendedContext.to_eng_string(Decimal('-123E-12'))
+'-123E-12'
+>>> ExtendedContext.to_eng_string(Decimal('7E-7'))
+'700E-9'
+>>> ExtendedContext.to_eng_string(Decimal('7E+1'))
+'70'
+>>> ExtendedContext.to_eng_string(Decimal('0E+1'))
+'0.00E+3'
+
 """
 a = _convert_other(a, raiseit=True)
 return a.to_eng_string(context=self)
diff --git a/lib-python/3/_pyio.py b/lib-python/3/_pyio.py
--- a/lib-python/3/_pyio.py
+++ b/lib-python/3/_pyio.py
@@ -276,7 +276,7 @@
 try:
 UnsupportedOperation = io.UnsupportedOperation
 except AttributeError:
-class UnsupportedOperation(ValueError, OSError):
+class UnsupportedOperation(OSError, ValueError):
 pass
 
 
diff --git a/lib-python/3/antigravity.py b/lib-python/3/antigravity.py
--- a/lib-python/3/antigravity.py
+++ b/lib-python/3/antigravity.py
@@ -2,7 +2,7 @@
 import webbrowser
 import hashlib
 
-webbrowser.open("http://xkcd.com/353/;)
+webbrowser.open("https://xkcd.com/353/;)
 
 def geohash(latitude, longitude, datedow):
 '''Compute geohash() using the Munroe algorithm.
diff --git a/lib-python/3/asyncio/base_events.py 
b/lib-python/3/asyncio/base_events.py
--- a/lib-python/3/asyncio/base_events.py
+++ b/lib-python/3/asyncio/base_events.py
@@ -13,7 +13,6 @@
 to modify the meaning of the API call itself.
 """
 
-
 import collections
 import concurrent.futures
 import heapq
@@ -28,6 +27,7 @@
 import traceback
 import sys
 import warnings
+import weakref
 
 from . 

[pypy-commit] pypy py3.5: hg merge

2017-02-05 Thread arigo
Author: Armin Rigo 
Branch: py3.5
Changeset: r89963:748aa3022295
Date: 2017-02-05 22:45 +0100
http://bitbucket.org/pypy/pypy/changeset/748aa3022295/

Log:hg merge

diff --git a/lib-python/2.7/weakref.py b/lib-python/2.7/weakref.py
--- a/lib-python/2.7/weakref.py
+++ b/lib-python/2.7/weakref.py
@@ -31,6 +31,26 @@
"WeakKeyDictionary", "ReferenceError", "ReferenceType", "ProxyType",
"CallableProxyType", "ProxyTypes", "WeakValueDictionary", 'WeakSet']
 
+try:
+from __pypy__ import delitem_if_value_is as _delitem_if_value_is
+except ImportError:
+def _delitem_if_value_is(d, key, value):
+try:
+if self.data[key] is value:  # fall-back: there is a potential
+# race condition in multithreaded programs HERE
+del self.data[key]
+except KeyError:
+pass
+
+def _remove_dead_weakref(d, key):
+try:
+wr = d[key]
+except KeyError:
+pass
+else:
+if wr() is None:
+_delitem_if_value_is(d, key, wr)
+
 
 class WeakValueDictionary(UserDict.UserDict):
 """Mapping class that references values weakly.
@@ -58,14 +78,9 @@
 if self._iterating:
 self._pending_removals.append(wr.key)
 else:
-# Changed this for PyPy: made more resistent.  The
-# issue is that in some corner cases, self.data
-# might already be changed or removed by the time
-# this weakref's callback is called.  If that is
-# the case, we don't want to randomly kill an
-# unrelated entry.
-if self.data.get(wr.key) is wr:
-del self.data[wr.key]
+# Atomic removal is necessary since this function
+# can be called asynchronously by the GC
+_delitem_if_value_is(self.data, wr.key, wr)
 self._remove = remove
 # A list of keys to be removed
 self._pending_removals = []
@@ -78,7 +93,8 @@
 # We shouldn't encounter any KeyError, because this method should
 # always be called *before* mutating the dict.
 while l:
-del d[l.pop()]
+key = l.pop()
+_remove_dead_weakref(d, key)
 
 def __getitem__(self, key):
 o = self.data[key]()
diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py
--- a/pypy/module/__pypy__/__init__.py
+++ b/pypy/module/__pypy__/__init__.py
@@ -78,6 +78,7 @@
 'add_memory_pressure'   : 'interp_magic.add_memory_pressure',
 'newdict'   : 'interp_dict.newdict',
 'reversed_dict' : 'interp_dict.reversed_dict',
+'delitem_if_value_is'   : 'interp_dict.delitem_if_value_is',
 'move_to_end'   : 'interp_dict.move_to_end',
 'strategy'  : 'interp_magic.strategy',  # dict,set,list
 'set_debug' : 'interp_magic.set_debug',
diff --git a/pypy/module/__pypy__/interp_dict.py 
b/pypy/module/__pypy__/interp_dict.py
--- a/pypy/module/__pypy__/interp_dict.py
+++ b/pypy/module/__pypy__/interp_dict.py
@@ -59,3 +59,16 @@
 if not isinstance(w_obj, W_DictMultiObject):
 raise OperationError(space.w_TypeError, space.w_None)
 return w_obj.nondescr_move_to_end(space, w_key, last)
+
+def delitem_if_value_is(space, w_obj, w_key, w_value):
+"""Atomic equivalent to: 'if dict.get(key) is value: del dict[key]'.
+
+SPECIAL USE CASES ONLY!  Avoid using on dicts which are specialized,
+e.g. to int or str keys, because it switches to the object strategy.
+Also, the 'is' operation is really pointer equality, so avoid using
+it if 'value' is an immutable object like int or str.
+"""
+from pypy.objspace.std.dictmultiobject import W_DictMultiObject
+if not isinstance(w_obj, W_DictMultiObject):
+raise OperationError(space.w_TypeError, space.w_None)
+return w_obj.nondescr_delitem_if_value_is(space, w_key, w_value)
diff --git a/pypy/module/cpyext/__init__.py b/pypy/module/cpyext/__init__.py
--- a/pypy/module/cpyext/__init__.py
+++ b/pypy/module/cpyext/__init__.py
@@ -40,6 +40,7 @@
 import pypy.module.cpyext.pyerrors
 import pypy.module.cpyext.typeobject
 import pypy.module.cpyext.object
+import pypy.module.cpyext.buffer
 import pypy.module.cpyext.bytesobject
 import pypy.module.cpyext.bytearrayobject
 import pypy.module.cpyext.tupleobject
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
@@ -126,7 +126,7 @@
 Py_TPFLAGS_HEAPTYPE
 Py_LT Py_LE Py_EQ Py_NE Py_GT Py_GE Py_MAX_NDIMS
 Py_CLEANUP_SUPPORTED
-PyBUF_FORMAT PyBUF_ND PyBUF_STRIDES
+PyBUF_FORMAT PyBUF_ND PyBUF_STRIDES PyBUF_WRITABLE PyBUF_SIMPLE
 """.split()
 for name in constant_names:
 

[pypy-commit] pypy py3.5: hg merge default

2017-02-05 Thread arigo
Author: Armin Rigo 
Branch: py3.5
Changeset: r89961:4bd2a3132a3f
Date: 2017-02-05 22:01 +0100
http://bitbucket.org/pypy/pypy/changeset/4bd2a3132a3f/

Log:hg merge default

diff --git a/lib-python/2.7/weakref.py b/lib-python/2.7/weakref.py
--- a/lib-python/2.7/weakref.py
+++ b/lib-python/2.7/weakref.py
@@ -31,6 +31,26 @@
"WeakKeyDictionary", "ReferenceError", "ReferenceType", "ProxyType",
"CallableProxyType", "ProxyTypes", "WeakValueDictionary", 'WeakSet']
 
+try:
+from __pypy__ import delitem_if_value_is as _delitem_if_value_is
+except ImportError:
+def _delitem_if_value_is(d, key, value):
+try:
+if self.data[key] is value:  # fall-back: there is a potential
+# race condition in multithreaded programs HERE
+del self.data[key]
+except KeyError:
+pass
+
+def _remove_dead_weakref(d, key):
+try:
+wr = d[key]
+except KeyError:
+pass
+else:
+if wr() is None:
+_delitem_if_value_is(d, key, wr)
+
 
 class WeakValueDictionary(UserDict.UserDict):
 """Mapping class that references values weakly.
@@ -58,14 +78,9 @@
 if self._iterating:
 self._pending_removals.append(wr.key)
 else:
-# Changed this for PyPy: made more resistent.  The
-# issue is that in some corner cases, self.data
-# might already be changed or removed by the time
-# this weakref's callback is called.  If that is
-# the case, we don't want to randomly kill an
-# unrelated entry.
-if self.data.get(wr.key) is wr:
-del self.data[wr.key]
+# Atomic removal is necessary since this function
+# can be called asynchronously by the GC
+_delitem_if_value_is(self.data, wr.key, wr)
 self._remove = remove
 # A list of keys to be removed
 self._pending_removals = []
@@ -78,7 +93,8 @@
 # We shouldn't encounter any KeyError, because this method should
 # always be called *before* mutating the dict.
 while l:
-del d[l.pop()]
+key = l.pop()
+_remove_dead_weakref(d, key)
 
 def __getitem__(self, key):
 o = self.data[key]()
diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py
--- a/pypy/module/__pypy__/__init__.py
+++ b/pypy/module/__pypy__/__init__.py
@@ -78,6 +78,7 @@
 'add_memory_pressure'   : 'interp_magic.add_memory_pressure',
 'newdict'   : 'interp_dict.newdict',
 'reversed_dict' : 'interp_dict.reversed_dict',
+'delitem_if_value_is'   : 'interp_dict.delitem_if_value_is',
 'move_to_end'   : 'interp_dict.move_to_end',
 'strategy'  : 'interp_magic.strategy',  # dict,set,list
 'set_debug' : 'interp_magic.set_debug',
diff --git a/pypy/module/__pypy__/interp_dict.py 
b/pypy/module/__pypy__/interp_dict.py
--- a/pypy/module/__pypy__/interp_dict.py
+++ b/pypy/module/__pypy__/interp_dict.py
@@ -59,3 +59,16 @@
 if not isinstance(w_obj, W_DictMultiObject):
 raise OperationError(space.w_TypeError, space.w_None)
 return w_obj.nondescr_move_to_end(space, w_key, last)
+
+def delitem_if_value_is(space, w_obj, w_key, w_value):
+"""Atomic equivalent to: 'if dict.get(key) is value: del dict[key]'.
+
+SPECIAL USE CASES ONLY!  Avoid using on dicts which are specialized,
+e.g. to int or str keys, because it switches to the object strategy.
+Also, the 'is' operation is really pointer equality, so avoid using
+it if 'value' is an immutable object like int or str.
+"""
+from pypy.objspace.std.dictmultiobject import W_DictMultiObject
+if not isinstance(w_obj, W_DictMultiObject):
+raise OperationError(space.w_TypeError, space.w_None)
+return w_obj.nondescr_delitem_if_value_is(space, w_key, w_value)
diff --git a/pypy/objspace/std/dictmultiobject.py 
b/pypy/objspace/std/dictmultiobject.py
--- a/pypy/objspace/std/dictmultiobject.py
+++ b/pypy/objspace/std/dictmultiobject.py
@@ -263,6 +263,14 @@
 for i in range(len(keys_w)):
 self.setitem(keys_w[i], values_w[i])
 
+def nondescr_delitem_if_value_is(self, space, w_key, w_value):
+"""Not exposed directly to app-level, but used by
+_weakref._remove_dead_weakref and via __pypy__.delitem_if_value_is().
+"""
+strategy = self.ensure_object_strategy()
+d = strategy.unerase(self.dstorage)
+objectmodel.delitem_if_value_is(d, w_key, w_value)
+
 def descr_clear(self, space):
 """D.clear() -> None.  Remove all items from D."""
 self.clear()
@@ -314,11 +322,12 @@
 F: D[k] 

[pypy-commit] pypy default: graft 6974fd5f5c47: Add __pypy__.move_to_end(), similar to

2017-02-05 Thread arigo
Author: Armin Rigo 
Branch: 
Changeset: r89959:e0ea69f0a7d8
Date: 2017-02-05 21:25 +0100
http://bitbucket.org/pypy/pypy/changeset/e0ea69f0a7d8/

Log:graft 6974fd5f5c47: Add __pypy__.move_to_end(), similar to
__pypy__.reversed_dict().

diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py
--- a/pypy/module/__pypy__/__init__.py
+++ b/pypy/module/__pypy__/__init__.py
@@ -80,6 +80,7 @@
 'newdict'   : 'interp_dict.newdict',
 'reversed_dict' : 'interp_dict.reversed_dict',
 'delitem_if_value_is'   : 'interp_dict.delitem_if_value_is',
+'move_to_end'   : 'interp_dict.move_to_end',
 'strategy'  : 'interp_magic.strategy',  # dict,set,list
 'specialized_zip_2_lists'   : 'interp_magic.specialized_zip_2_lists',
 'set_debug' : 'interp_magic.set_debug',
diff --git a/pypy/module/__pypy__/interp_dict.py 
b/pypy/module/__pypy__/interp_dict.py
--- a/pypy/module/__pypy__/interp_dict.py
+++ b/pypy/module/__pypy__/interp_dict.py
@@ -57,3 +57,14 @@
 if not isinstance(w_obj, W_DictMultiObject):
 raise OperationError(space.w_TypeError, space.w_None)
 return w_obj.nondescr_delitem_if_value_is(space, w_key, w_value)
+
+@unwrap_spec(last=bool)
+def move_to_end(space, w_obj, w_key, last=True):
+"""Move the key in a dictionary object into the first or last position.
+
+This is used in Python 3.x to implement OrderedDict.move_to_end().
+"""
+from pypy.objspace.std.dictmultiobject import W_DictMultiObject
+if not isinstance(w_obj, W_DictMultiObject):
+raise OperationError(space.w_TypeError, space.w_None)
+return w_obj.nondescr_move_to_end(space, w_key, last)
diff --git a/pypy/objspace/std/dictmultiobject.py 
b/pypy/objspace/std/dictmultiobject.py
--- a/pypy/objspace/std/dictmultiobject.py
+++ b/pypy/objspace/std/dictmultiobject.py
@@ -307,6 +307,37 @@
 """D.has_key(k) -> True if D has a key k, else False"""
 return space.newbool(self.getitem(w_key) is not None)
 
+def nondescr_move_to_end(self, space, w_key, last_flag):
+"""Not exposed directly to app-level, but via __pypy__.move_to_end().
+"""
+strategy = self.get_strategy()
+if strategy.has_move_to_end:
+strategy.move_to_end(self, w_key, last_flag)
+else:
+# fall-back
+w_value = self.getitem(w_key)
+if w_value is None:
+space.raise_key_error(w_key)
+else:
+self.delitem(w_key)
+if last_flag:
+self.setitem(w_key, w_value)
+else:
+# *very slow* fall-back
+keys_w = []
+values_w = []
+iteratorimplementation = self.iteritems()
+while True:
+w_k, w_v = iteratorimplementation.next_item()
+if w_k is None:
+break
+keys_w.append(w_k)
+values_w.append(w_v)
+self.clear()
+self.setitem(w_key, w_value)
+for i in range(len(keys_w)):
+self.setitem(keys_w[i], values_w[i])
+
 def descr_clear(self, space):
 """D.clear() -> None.  Remove all items from D."""
 self.clear()
@@ -578,7 +609,9 @@
 raise NotImplementedError
 
 has_iterreversed = False
-# no 'getiterreversed': no default implementation available
+has_move_to_end = False
+# no 'getiterreversed' and no 'move_to_end': no default
+# implementation available
 
 def rev_update1_dict_dict(self, w_dict, w_updatedict):
 iteritems = self.iteritems(w_dict)
@@ -849,6 +882,9 @@
 dictimpl.iterreversed = iterreversed
 dictimpl.has_iterreversed = True
 
+if hasattr(dictimpl, 'move_to_end'):
+dictimpl.has_move_to_end = True
+
 @jit.look_inside_iff(lambda self, w_dict, w_updatedict:
  w_dict_unrolling_heuristic(w_dict))
 def rev_update1_dict_dict(self, w_dict, w_updatedict):
@@ -1013,6 +1049,15 @@
 def getiterreversed(self, w_dict):
 return objectmodel.reversed_dict(self.unerase(w_dict.dstorage))
 
+def move_to_end(self, w_dict, w_key, last_flag):
+if self.is_correct_type(w_key):
+d = self.unerase(w_dict.dstorage)
+key = self.unwrap(w_key)
+objectmodel.move_to_end(d, key, last_flag)
+else:
+self.switch_to_object_strategy(w_dict)
+w_dict.nondescr_move_to_end(w_dict.space, w_key, last_flag)
+
 def prepare_update(self, w_dict, num_extra):
 objectmodel.prepare_dict_update(self.unerase(w_dict.dstorage),
 num_extra)
diff --git a/pypy/objspace/std/test/test_dictmultiobject.py 

[pypy-commit] pypy default: merge heads

2017-02-05 Thread arigo
Author: Armin Rigo 
Branch: 
Changeset: r89960:357c149fd26e
Date: 2017-02-05 21:49 +0100
http://bitbucket.org/pypy/pypy/changeset/357c149fd26e/

Log:merge heads

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
@@ -126,7 +126,7 @@
 METH_NOARGS METH_VARARGS METH_KEYWORDS METH_O Py_TPFLAGS_HAVE_INPLACEOPS
 Py_TPFLAGS_HEAPTYPE Py_TPFLAGS_HAVE_CLASS Py_TPFLAGS_HAVE_NEWBUFFER
 Py_LT Py_LE Py_EQ Py_NE Py_GT Py_GE Py_TPFLAGS_CHECKTYPES Py_MAX_NDIMS
-PyBUF_FORMAT PyBUF_ND PyBUF_STRIDES
+PyBUF_FORMAT PyBUF_ND PyBUF_STRIDES PyBUF_WRITABLE
 """.split()
 for name in constant_names:
 setattr(CConfig_constants, name, rffi_platform.ConstantInteger(name))
diff --git a/pypy/module/cpyext/buffer.py b/pypy/module/cpyext/buffer.py
--- a/pypy/module/cpyext/buffer.py
+++ b/pypy/module/cpyext/buffer.py
@@ -1,7 +1,10 @@
-from rpython.rtyper.lltypesystem import rffi
+from rpython.rtyper.lltypesystem import rffi, lltype
+from pypy.interpreter.error import oefmt
 from pypy.module.cpyext.api import (
-cpython_api, CANNOT_FAIL, Py_TPFLAGS_HAVE_NEWBUFFER, cts)
-from pypy.module.cpyext.pyobject import PyObject
+cpython_api, CANNOT_FAIL, Py_TPFLAGS_HAVE_NEWBUFFER, cts, Py_buffer,
+Py_ssize_t, Py_ssize_tP,
+PyBUF_WRITABLE, PyBUF_FORMAT, PyBUF_ND, PyBUF_STRIDES)
+from pypy.module.cpyext.pyobject import PyObject, Py_IncRef, Py_DecRef
 
 @cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL)
 def PyObject_CheckBuffer(space, pyobj):
@@ -11,7 +14,52 @@
 if (flags & Py_TPFLAGS_HAVE_NEWBUFFER and as_buffer.c_bf_getbuffer):
 return 1
 name = rffi.charp2str(cts.cast('char*', pyobj.c_ob_type.c_tp_name))
-if  name in ('str', 'bytes'):
+if name in ('str', 'bytes'):
 # XXX remove once wrapper of __buffer__ -> bf_getbuffer works
 return 1
 return 0
+
+@cpython_api([lltype.Ptr(Py_buffer), PyObject, rffi.VOIDP, Py_ssize_t,
+  lltype.Signed, lltype.Signed], rffi.INT, error=-1)
+def PyBuffer_FillInfo(space, view, obj, buf, length, readonly, flags):
+"""
+Fills in a buffer-info structure correctly for an exporter that can only
+share a contiguous chunk of memory of "unsigned bytes" of the given
+length. Returns 0 on success and -1 (with raising an error) on error.
+"""
+if flags & PyBUF_WRITABLE and readonly:
+raise oefmt(space.w_ValueError, "Object is not writable")
+view.c_buf = buf
+view.c_len = length
+view.c_obj = obj
+if obj:
+Py_IncRef(space, obj)
+view.c_itemsize = 1
+rffi.setintfield(view, 'c_readonly', readonly)
+rffi.setintfield(view, 'c_ndim', 1)
+view.c_format = lltype.nullptr(rffi.CCHARP.TO)
+if (flags & PyBUF_FORMAT) == PyBUF_FORMAT:
+view.c_format = rffi.str2charp("B")
+view.c_shape = lltype.nullptr(Py_ssize_tP.TO)
+if (flags & PyBUF_ND) == PyBUF_ND:
+view.c_shape = rffi.cast(Py_ssize_tP, view.c__shape)
+view.c_shape[0] = view.c_len
+view.c_strides = lltype.nullptr(Py_ssize_tP.TO)
+if (flags & PyBUF_STRIDES) == PyBUF_STRIDES:
+view.c_strides = rffi.cast(Py_ssize_tP, view.c__strides)
+view.c_strides[0] = view.c_itemsize
+view.c_suboffsets = lltype.nullptr(Py_ssize_tP.TO)
+view.c_internal = lltype.nullptr(rffi.VOIDP.TO)
+
+return 0
+
+
+@cpython_api([lltype.Ptr(Py_buffer)], lltype.Void, error=CANNOT_FAIL)
+def PyBuffer_Release(space, view):
+"""
+Release the buffer view. This should be called when the buffer is
+no longer being used as it may free memory from it
+"""
+Py_DecRef(space, view.c_obj)
+view.c_obj = lltype.nullptr(PyObject.TO)
+# XXX do other fields leak memory?
diff --git a/pypy/module/cpyext/object.py b/pypy/module/cpyext/object.py
--- a/pypy/module/cpyext/object.py
+++ b/pypy/module/cpyext/object.py
@@ -1,13 +1,12 @@
 from rpython.rtyper.lltypesystem import rffi, lltype
 from pypy.module.cpyext.api import (
 cpython_api, generic_cpy_call, CANNOT_FAIL, Py_ssize_t, Py_ssize_tP,
-PyVarObject, Py_buffer, size_t, slot_function,
-PyBUF_FORMAT, PyBUF_ND, PyBUF_STRIDES,
+PyVarObject, size_t, slot_function,
 Py_TPFLAGS_HEAPTYPE, Py_LT, Py_LE, Py_EQ, Py_NE, Py_GT,
 Py_GE, CONST_STRING, CONST_STRINGP, FILEP, fwrite)
 from pypy.module.cpyext.pyobject import (
-PyObject, PyObjectP, create_ref, from_ref, Py_IncRef, Py_DecRef,
-get_typedescr, _Py_NewReference)
+PyObject, PyObjectP, from_ref, Py_IncRef, Py_DecRef,
+get_typedescr)
 from pypy.module.cpyext.typeobject import PyTypeObjectPtr
 from pypy.module.cpyext.pyerrors import PyErr_NoMemory, PyErr_BadInternalCall
 from pypy.objspace.std.typeobject import W_TypeObject
@@ -476,51 +475,3 @@
 with rffi.scoped_nonmovingbuffer(data) as buf:
 fwrite(buf, 1, count, fp)
 return 0
-
-
-PyBUF_WRITABLE = 0x0001  # Copied from object.h
-
-@cpython_api([lltype.Ptr(Py_buffer), PyObject, rffi.VOIDP, 

[pypy-commit] pypy default: Add objectmodel.delitem_if_value_is(), to be used next

2017-02-05 Thread arigo
Author: Armin Rigo 
Branch: 
Changeset: r89957:bfc27e0e9d42
Date: 2017-02-05 19:46 +0100
http://bitbucket.org/pypy/pypy/changeset/bfc27e0e9d42/

Log:Add objectmodel.delitem_if_value_is(), to be used next

diff --git a/rpython/annotator/unaryop.py b/rpython/annotator/unaryop.py
--- a/rpython/annotator/unaryop.py
+++ b/rpython/annotator/unaryop.py
@@ -575,6 +575,10 @@
 pair(self, s_key).delitem()
 method_delitem_with_hash.can_only_throw = _dict_can_only_throw_keyerror
 
+def method_delitem_if_value_is(self, s_key, s_value):
+pair(self, s_key).setitem(s_value)
+pair(self, s_key).delitem()
+
 class __extend__(SomeOrderedDict):
 
 def method_move_to_end(self, s_key, s_last):
diff --git a/rpython/rlib/objectmodel.py b/rpython/rlib/objectmodel.py
--- a/rpython/rlib/objectmodel.py
+++ b/rpython/rlib/objectmodel.py
@@ -934,6 +934,20 @@
 return
 d.delitem_with_hash(key, h)
 
+@specialize.call_location()
+def delitem_if_value_is(d, key, value):
+"""Same as 'if d.get(key) is value: del d[key]'.  It is safe even in
+case 'd' is an r_dict and the lookup involves callbacks that might
+release the GIL."""
+if not we_are_translated():
+try:
+if d[key] is value:
+del d[key]
+except KeyError:
+pass
+return
+d.delitem_if_value_is(key, value)
+
 def _untranslated_move_to_end(d, key, last):
 "NOT_RPYTHON"
 value = d.pop(key)
diff --git a/rpython/rlib/test/test_objectmodel.py 
b/rpython/rlib/test/test_objectmodel.py
--- a/rpython/rlib/test/test_objectmodel.py
+++ b/rpython/rlib/test/test_objectmodel.py
@@ -7,7 +7,7 @@
 resizelist_hint, is_annotation_constant, always_inline, NOT_CONSTANT,
 iterkeys_with_hash, iteritems_with_hash, contains_with_hash,
 setitem_with_hash, getitem_with_hash, delitem_with_hash, import_from_mixin,
-fetch_translated_config, try_inline, move_to_end)
+fetch_translated_config, try_inline, delitem_if_value_is, move_to_end)
 from rpython.translator.translator import TranslationContext, graphof
 from rpython.rtyper.test.tool import BaseRtypingTest
 from rpython.rtyper.test.test_llinterp import interpret
@@ -661,6 +661,24 @@
 f(29)
 interpret(f, [27])
 
+def test_delitem_if_value_is():
+class X:
+pass
+def f(i):
+x42 = X()
+x612 = X()
+d = {i + .5: x42, i + .6: x612}
+delitem_if_value_is(d, i + .5, x612)
+assert (i + .5) in d
+delitem_if_value_is(d, i + .5, x42)
+assert (i + .5) not in d
+delitem_if_value_is(d, i + .5, x612)
+assert (i + .5) not in d
+return 0
+
+f(29)
+interpret(f, [27])
+
 def test_rdict_with_hash():
 def f(i):
 d = r_dict(strange_key_eq, strange_key_hash)
diff --git a/rpython/rtyper/lltypesystem/rordereddict.py 
b/rpython/rtyper/lltypesystem/rordereddict.py
--- a/rpython/rtyper/lltypesystem/rordereddict.py
+++ b/rpython/rtyper/lltypesystem/rordereddict.py
@@ -407,6 +407,12 @@
 hop.exception_is_here()
 hop.gendirectcall(ll_dict_delitem_with_hash, v_dict, v_key, v_hash)
 
+def rtype_method_delitem_if_value_is(self, hop):
+v_dict, v_key, v_value = hop.inputargs(
+self, self.key_repr, self.value_repr)
+hop.exception_cannot_occur()
+hop.gendirectcall(ll_dict_delitem_if_value_is, v_dict, v_key, v_value)
+
 def rtype_method_move_to_end(self, hop):
 v_dict, v_key, v_last = hop.inputargs(
 self, self.key_repr, lltype.Bool)
@@ -821,6 +827,15 @@
 raise KeyError
 _ll_dict_del(d, hash, index)
 
+def ll_dict_delitem_if_value_is(d, key, value):
+hash = d.keyhash(key)
+index = d.lookup_function(d, key, hash, FLAG_LOOKUP)
+if index < 0:
+return
+if d.entries[index].value != value:
+return
+_ll_dict_del(d, hash, index)
+
 def _ll_dict_del_entry(d, index):
 d.entries.mark_deleted(index)
 d.num_live_items -= 1
___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit


[pypy-commit] pypy default: Use objectmodel.delitem_if_value_is() to fix lib-python/2.7/weakref.py

2017-02-05 Thread arigo
Author: Armin Rigo 
Branch: 
Changeset: r89958:cba1fc5e5dcf
Date: 2017-02-05 20:54 +0100
http://bitbucket.org/pypy/pypy/changeset/cba1fc5e5dcf/

Log:Use objectmodel.delitem_if_value_is() to fix lib-
python/2.7/weakref.py

diff --git a/lib-python/2.7/weakref.py b/lib-python/2.7/weakref.py
--- a/lib-python/2.7/weakref.py
+++ b/lib-python/2.7/weakref.py
@@ -31,6 +31,26 @@
"WeakKeyDictionary", "ReferenceError", "ReferenceType", "ProxyType",
"CallableProxyType", "ProxyTypes", "WeakValueDictionary", 'WeakSet']
 
+try:
+from __pypy__ import delitem_if_value_is as _delitem_if_value_is
+except ImportError:
+def _delitem_if_value_is(d, key, value):
+try:
+if self.data[key] is value:  # fall-back: there is a potential
+# race condition in multithreaded programs HERE
+del self.data[key]
+except KeyError:
+pass
+
+def _remove_dead_weakref(d, key):
+try:
+wr = d[key]
+except KeyError:
+pass
+else:
+if wr() is None:
+_delitem_if_value_is(d, key, wr)
+
 
 class WeakValueDictionary(UserDict.UserDict):
 """Mapping class that references values weakly.
@@ -58,14 +78,9 @@
 if self._iterating:
 self._pending_removals.append(wr.key)
 else:
-# Changed this for PyPy: made more resistent.  The
-# issue is that in some corner cases, self.data
-# might already be changed or removed by the time
-# this weakref's callback is called.  If that is
-# the case, we don't want to randomly kill an
-# unrelated entry.
-if self.data.get(wr.key) is wr:
-del self.data[wr.key]
+# Atomic removal is necessary since this function
+# can be called asynchronously by the GC
+_delitem_if_value_is(self.data, wr.key, wr)
 self._remove = remove
 # A list of keys to be removed
 self._pending_removals = []
@@ -78,7 +93,8 @@
 # We shouldn't encounter any KeyError, because this method should
 # always be called *before* mutating the dict.
 while l:
-del d[l.pop()]
+key = l.pop()
+_remove_dead_weakref(d, key)
 
 def __getitem__(self, key):
 o = self.data[key]()
diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py
--- a/pypy/module/__pypy__/__init__.py
+++ b/pypy/module/__pypy__/__init__.py
@@ -79,6 +79,7 @@
 'add_memory_pressure'   : 'interp_magic.add_memory_pressure',
 'newdict'   : 'interp_dict.newdict',
 'reversed_dict' : 'interp_dict.reversed_dict',
+'delitem_if_value_is'   : 'interp_dict.delitem_if_value_is',
 'strategy'  : 'interp_magic.strategy',  # dict,set,list
 'specialized_zip_2_lists'   : 'interp_magic.specialized_zip_2_lists',
 'set_debug' : 'interp_magic.set_debug',
diff --git a/pypy/module/__pypy__/interp_dict.py 
b/pypy/module/__pypy__/interp_dict.py
--- a/pypy/module/__pypy__/interp_dict.py
+++ b/pypy/module/__pypy__/interp_dict.py
@@ -44,3 +44,16 @@
 if not isinstance(w_obj, W_DictMultiObject):
 raise OperationError(space.w_TypeError, space.w_None)
 return w_obj.nondescr_reversed_dict(space)
+
+def delitem_if_value_is(space, w_obj, w_key, w_value):
+"""Atomic equivalent to: 'if dict.get(key) is value: del dict[key]'.
+
+SPECIAL USE CASES ONLY!  Avoid using on dicts which are specialized,
+e.g. to int or str keys, because it switches to the object strategy.
+Also, the 'is' operation is really pointer equality, so avoid using
+it if 'value' is an immutable object like int or str.
+"""
+from pypy.objspace.std.dictmultiobject import W_DictMultiObject
+if not isinstance(w_obj, W_DictMultiObject):
+raise OperationError(space.w_TypeError, space.w_None)
+return w_obj.nondescr_delitem_if_value_is(space, w_key, w_value)
diff --git a/pypy/objspace/std/dictmultiobject.py 
b/pypy/objspace/std/dictmultiobject.py
--- a/pypy/objspace/std/dictmultiobject.py
+++ b/pypy/objspace/std/dictmultiobject.py
@@ -283,6 +283,14 @@
 w_keys = self.w_keys()
 return space.call_method(w_keys, '__reversed__')
 
+def nondescr_delitem_if_value_is(self, space, w_key, w_value):
+"""Not exposed directly to app-level, but used by
+_weakref._remove_dead_weakref and via __pypy__.delitem_if_value_is().
+"""
+strategy = self.ensure_object_strategy()
+d = strategy.unerase(self.dstorage)
+objectmodel.delitem_if_value_is(d, w_key, w_value)
+
 def descr_viewitems(self, space):
 """D.viewitems() -> a set-like object providing a view on D's 

[pypy-commit] pypy py3.5: fix minor merge error

2017-02-05 Thread arigo
Author: Armin Rigo 
Branch: py3.5
Changeset: r89956:25ba5fb90782
Date: 2017-02-05 21:44 +0100
http://bitbucket.org/pypy/pypy/changeset/25ba5fb90782/

Log:fix minor merge error

diff --git a/pypy/module/_cffi_backend/test/test_ffi_obj.py 
b/pypy/module/_cffi_backend/test/test_ffi_obj.py
--- a/pypy/module/_cffi_backend/test/test_ffi_obj.py
+++ b/pypy/module/_cffi_backend/test/test_ffi_obj.py
@@ -258,8 +258,6 @@
 assert ffi.buffer(a)[:] == b'\x05\x06\x07'
 assert ffi.buffer(cdata=a, size=2)[:] == b'\x05\x06'
 assert type(ffi.buffer(a)) is ffi.buffer
-assert ffi.buffer(cdata=a, size=2)[:] == b'\x05\x06'
-assert type(ffi.buffer(a)) is ffi.buffer
 
 def test_ffi_from_buffer(self):
 import _cffi_backend as _cffi1_backend
___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit


[pypy-commit] pypy py3.5: hg merge default

2017-02-05 Thread rlamy
Author: Ronan Lamy 
Branch: py3.5
Changeset: r89955:b32bdcb0c782
Date: 2017-02-05 20:38 +
http://bitbucket.org/pypy/pypy/changeset/b32bdcb0c782/

Log:hg merge default

diff --git a/pypy/module/_cffi_backend/test/test_ffi_obj.py 
b/pypy/module/_cffi_backend/test/test_ffi_obj.py
--- a/pypy/module/_cffi_backend/test/test_ffi_obj.py
+++ b/pypy/module/_cffi_backend/test/test_ffi_obj.py
@@ -258,6 +258,8 @@
 assert ffi.buffer(a)[:] == b'\x05\x06\x07'
 assert ffi.buffer(cdata=a, size=2)[:] == b'\x05\x06'
 assert type(ffi.buffer(a)) is ffi.buffer
+assert ffi.buffer(cdata=a, size=2)[:] == b'\x05\x06'
+assert type(ffi.buffer(a)) is ffi.buffer
 
 def test_ffi_from_buffer(self):
 import _cffi_backend as _cffi1_backend
___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit


[pypy-commit] pypy py3.5: Move buffer functions to pypy.module.cpyext.buffer

2017-02-05 Thread rlamy
Author: Ronan Lamy 
Branch: py3.5
Changeset: r89954:1a3f307b706d
Date: 2017-02-05 20:15 +
http://bitbucket.org/pypy/pypy/changeset/1a3f307b706d/

Log:Move buffer functions to pypy.module.cpyext.buffer

diff --git a/pypy/module/cpyext/__init__.py b/pypy/module/cpyext/__init__.py
--- a/pypy/module/cpyext/__init__.py
+++ b/pypy/module/cpyext/__init__.py
@@ -40,6 +40,7 @@
 import pypy.module.cpyext.pyerrors
 import pypy.module.cpyext.typeobject
 import pypy.module.cpyext.object
+import pypy.module.cpyext.buffer
 import pypy.module.cpyext.bytesobject
 import pypy.module.cpyext.bytearrayobject
 import pypy.module.cpyext.tupleobject
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
@@ -126,7 +126,7 @@
 Py_TPFLAGS_HEAPTYPE
 Py_LT Py_LE Py_EQ Py_NE Py_GT Py_GE Py_MAX_NDIMS
 Py_CLEANUP_SUPPORTED
-PyBUF_FORMAT PyBUF_ND PyBUF_STRIDES
+PyBUF_FORMAT PyBUF_ND PyBUF_STRIDES PyBUF_WRITABLE PyBUF_SIMPLE
 """.split()
 for name in constant_names:
 setattr(CConfig_constants, name, rffi_platform.ConstantInteger(name))
diff --git a/pypy/module/cpyext/buffer.py b/pypy/module/cpyext/buffer.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/buffer.py
@@ -0,0 +1,72 @@
+from rpython.rtyper.lltypesystem import rffi, lltype
+from pypy.interpreter.error import oefmt
+from pypy.module.cpyext.api import (
+cpython_api, Py_buffer, Py_ssize_t, Py_ssize_tP, CONST_STRINGP,
+generic_cpy_call,
+PyBUF_WRITABLE, PyBUF_FORMAT, PyBUF_ND, PyBUF_STRIDES, PyBUF_SIMPLE)
+from pypy.module.cpyext.pyobject import PyObject, Py_IncRef, Py_DecRef
+
+@cpython_api([PyObject, CONST_STRINGP, Py_ssize_tP], rffi.INT_real, error=-1)
+def PyObject_AsCharBuffer(space, obj, bufferp, sizep):
+"""Returns a pointer to a read-only memory location usable as
+character-based input.  The obj argument must support the single-segment
+character buffer interface.  On success, returns 0, sets buffer to the
+memory location and size to the buffer length.  Returns -1 and sets a
+TypeError on error.
+"""
+pto = obj.c_ob_type
+pb = pto.c_tp_as_buffer
+if not (pb and pb.c_bf_getbuffer):
+raise oefmt(space.w_TypeError,
+"expected an object with the buffer interface")
+with lltype.scoped_alloc(Py_buffer) as view:
+ret = generic_cpy_call(
+space, pb.c_bf_getbuffer,
+obj, view, rffi.cast(rffi.INT_real, PyBUF_SIMPLE))
+if rffi.cast(lltype.Signed, ret) == -1:
+return -1
+
+bufferp[0] = rffi.cast(rffi.CCHARP, view.c_buf)
+sizep[0] = view.c_len
+
+if pb.c_bf_releasebuffer:
+generic_cpy_call(space, pb.c_bf_releasebuffer,
+ obj, view)
+Py_DecRef(space, view.c_obj)
+return 0
+
+
+@cpython_api([lltype.Ptr(Py_buffer), PyObject, rffi.VOIDP, Py_ssize_t,
+  lltype.Signed, lltype.Signed], rffi.INT, error=-1)
+def PyBuffer_FillInfo(space, view, obj, buf, length, readonly, flags):
+"""
+Fills in a buffer-info structure correctly for an exporter that can only
+share a contiguous chunk of memory of "unsigned bytes" of the given
+length. Returns 0 on success and -1 (with raising an error) on error.
+"""
+flags = rffi.cast(lltype.Signed, flags)
+if flags & PyBUF_WRITABLE and readonly:
+raise oefmt(space.w_ValueError, "Object is not writable")
+view.c_buf = buf
+view.c_len = length
+view.c_obj = obj
+if obj:
+Py_IncRef(space, obj)
+view.c_itemsize = 1
+rffi.setintfield(view, 'c_readonly', readonly)
+rffi.setintfield(view, 'c_ndim', 1)
+view.c_format = lltype.nullptr(rffi.CCHARP.TO)
+if (flags & PyBUF_FORMAT) == PyBUF_FORMAT:
+view.c_format = rffi.str2charp("B")
+view.c_shape = lltype.nullptr(Py_ssize_tP.TO)
+if (flags & PyBUF_ND) == PyBUF_ND:
+view.c_shape = rffi.cast(Py_ssize_tP, view.c__shape)
+view.c_shape[0] = view.c_len
+view.c_strides = lltype.nullptr(Py_ssize_tP.TO)
+if (flags & PyBUF_STRIDES) == PyBUF_STRIDES:
+view.c_strides = rffi.cast(Py_ssize_tP, view.c__strides)
+view.c_strides[0] = view.c_itemsize
+view.c_suboffsets = lltype.nullptr(Py_ssize_tP.TO)
+view.c_internal = lltype.nullptr(rffi.VOIDP.TO)
+
+return 0
diff --git a/pypy/module/cpyext/object.py b/pypy/module/cpyext/object.py
--- a/pypy/module/cpyext/object.py
+++ b/pypy/module/cpyext/object.py
@@ -1,13 +1,11 @@
 from rpython.rtyper.lltypesystem import rffi, lltype
 from pypy.module.cpyext.api import (
-cpython_api, generic_cpy_call, CANNOT_FAIL, Py_ssize_t, Py_ssize_tP,
-PyVarObject, Py_buffer, size_t, slot_function, cts,
-PyBUF_FORMAT, PyBUF_ND, PyBUF_STRIDES,
+cpython_api, generic_cpy_call, CANNOT_FAIL, Py_ssize_t,
+PyVarObject, size_t, slot_function, cts,
 Py_TPFLAGS_HEAPTYPE, Py_LT, Py_LE, Py_EQ, Py_NE, Py_GT,
-Py_GE, 

[pypy-commit] pypy default: Move buffer functions to pypy.module.cpyext.buffer

2017-02-05 Thread rlamy
Author: Ronan Lamy 
Branch: 
Changeset: r89953:ad2c1430f189
Date: 2017-02-05 19:38 +
http://bitbucket.org/pypy/pypy/changeset/ad2c1430f189/

Log:Move buffer functions to pypy.module.cpyext.buffer

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
@@ -126,7 +126,7 @@
 METH_NOARGS METH_VARARGS METH_KEYWORDS METH_O Py_TPFLAGS_HAVE_INPLACEOPS
 Py_TPFLAGS_HEAPTYPE Py_TPFLAGS_HAVE_CLASS Py_TPFLAGS_HAVE_NEWBUFFER
 Py_LT Py_LE Py_EQ Py_NE Py_GT Py_GE Py_TPFLAGS_CHECKTYPES Py_MAX_NDIMS
-PyBUF_FORMAT PyBUF_ND PyBUF_STRIDES
+PyBUF_FORMAT PyBUF_ND PyBUF_STRIDES PyBUF_WRITABLE
 """.split()
 for name in constant_names:
 setattr(CConfig_constants, name, rffi_platform.ConstantInteger(name))
diff --git a/pypy/module/cpyext/buffer.py b/pypy/module/cpyext/buffer.py
--- a/pypy/module/cpyext/buffer.py
+++ b/pypy/module/cpyext/buffer.py
@@ -1,7 +1,10 @@
-from rpython.rtyper.lltypesystem import rffi
+from rpython.rtyper.lltypesystem import rffi, lltype
+from pypy.interpreter.error import oefmt
 from pypy.module.cpyext.api import (
-cpython_api, CANNOT_FAIL, Py_TPFLAGS_HAVE_NEWBUFFER, cts)
-from pypy.module.cpyext.pyobject import PyObject
+cpython_api, CANNOT_FAIL, Py_TPFLAGS_HAVE_NEWBUFFER, cts, Py_buffer,
+Py_ssize_t, Py_ssize_tP,
+PyBUF_WRITABLE, PyBUF_FORMAT, PyBUF_ND, PyBUF_STRIDES)
+from pypy.module.cpyext.pyobject import PyObject, Py_IncRef, Py_DecRef
 
 @cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL)
 def PyObject_CheckBuffer(space, pyobj):
@@ -11,7 +14,52 @@
 if (flags & Py_TPFLAGS_HAVE_NEWBUFFER and as_buffer.c_bf_getbuffer):
 return 1
 name = rffi.charp2str(cts.cast('char*', pyobj.c_ob_type.c_tp_name))
-if  name in ('str', 'bytes'):
+if name in ('str', 'bytes'):
 # XXX remove once wrapper of __buffer__ -> bf_getbuffer works
 return 1
 return 0
+
+@cpython_api([lltype.Ptr(Py_buffer), PyObject, rffi.VOIDP, Py_ssize_t,
+  lltype.Signed, lltype.Signed], rffi.INT, error=-1)
+def PyBuffer_FillInfo(space, view, obj, buf, length, readonly, flags):
+"""
+Fills in a buffer-info structure correctly for an exporter that can only
+share a contiguous chunk of memory of "unsigned bytes" of the given
+length. Returns 0 on success and -1 (with raising an error) on error.
+"""
+if flags & PyBUF_WRITABLE and readonly:
+raise oefmt(space.w_ValueError, "Object is not writable")
+view.c_buf = buf
+view.c_len = length
+view.c_obj = obj
+if obj:
+Py_IncRef(space, obj)
+view.c_itemsize = 1
+rffi.setintfield(view, 'c_readonly', readonly)
+rffi.setintfield(view, 'c_ndim', 1)
+view.c_format = lltype.nullptr(rffi.CCHARP.TO)
+if (flags & PyBUF_FORMAT) == PyBUF_FORMAT:
+view.c_format = rffi.str2charp("B")
+view.c_shape = lltype.nullptr(Py_ssize_tP.TO)
+if (flags & PyBUF_ND) == PyBUF_ND:
+view.c_shape = rffi.cast(Py_ssize_tP, view.c__shape)
+view.c_shape[0] = view.c_len
+view.c_strides = lltype.nullptr(Py_ssize_tP.TO)
+if (flags & PyBUF_STRIDES) == PyBUF_STRIDES:
+view.c_strides = rffi.cast(Py_ssize_tP, view.c__strides)
+view.c_strides[0] = view.c_itemsize
+view.c_suboffsets = lltype.nullptr(Py_ssize_tP.TO)
+view.c_internal = lltype.nullptr(rffi.VOIDP.TO)
+
+return 0
+
+
+@cpython_api([lltype.Ptr(Py_buffer)], lltype.Void, error=CANNOT_FAIL)
+def PyBuffer_Release(space, view):
+"""
+Release the buffer view. This should be called when the buffer is
+no longer being used as it may free memory from it
+"""
+Py_DecRef(space, view.c_obj)
+view.c_obj = lltype.nullptr(PyObject.TO)
+# XXX do other fields leak memory?
diff --git a/pypy/module/cpyext/object.py b/pypy/module/cpyext/object.py
--- a/pypy/module/cpyext/object.py
+++ b/pypy/module/cpyext/object.py
@@ -1,13 +1,12 @@
 from rpython.rtyper.lltypesystem import rffi, lltype
 from pypy.module.cpyext.api import (
 cpython_api, generic_cpy_call, CANNOT_FAIL, Py_ssize_t, Py_ssize_tP,
-PyVarObject, Py_buffer, size_t, slot_function,
-PyBUF_FORMAT, PyBUF_ND, PyBUF_STRIDES,
+PyVarObject, size_t, slot_function,
 Py_TPFLAGS_HEAPTYPE, Py_LT, Py_LE, Py_EQ, Py_NE, Py_GT,
 Py_GE, CONST_STRING, CONST_STRINGP, FILEP, fwrite)
 from pypy.module.cpyext.pyobject import (
-PyObject, PyObjectP, create_ref, from_ref, Py_IncRef, Py_DecRef,
-get_typedescr, _Py_NewReference)
+PyObject, PyObjectP, from_ref, Py_IncRef, Py_DecRef,
+get_typedescr)
 from pypy.module.cpyext.typeobject import PyTypeObjectPtr
 from pypy.module.cpyext.pyerrors import PyErr_NoMemory, PyErr_BadInternalCall
 from pypy.objspace.std.typeobject import W_TypeObject
@@ -476,51 +475,3 @@
 with rffi.scoped_nonmovingbuffer(data) as buf:
 fwrite(buf, 1, count, fp)
 return 0
-
-
-PyBUF_WRITABLE = 0x0001  # Copied from object.h
-

[pypy-commit] pypy dict-move-to-end: ready to merge

2017-02-05 Thread arigo
Author: Armin Rigo 
Branch: dict-move-to-end
Changeset: r89951:8a180d361371
Date: 2017-02-05 19:40 +0100
http://bitbucket.org/pypy/pypy/changeset/8a180d361371/

Log:ready to merge

___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit


[pypy-commit] pypy default: hg merge dict-move-to-end

2017-02-05 Thread arigo
Author: Armin Rigo 
Branch: 
Changeset: r89952:72b034121391
Date: 2017-02-05 19:41 +0100
http://bitbucket.org/pypy/pypy/changeset/72b034121391/

Log:hg merge dict-move-to-end

Implement move_to_end(last=True/False) on RPython ordered dicts.
Minor clean-ups in the ordered dict implementation.

diff --git a/rpython/annotator/unaryop.py b/rpython/annotator/unaryop.py
--- a/rpython/annotator/unaryop.py
+++ b/rpython/annotator/unaryop.py
@@ -14,7 +14,7 @@
 SomeUnicodeCodePoint, SomeInstance, SomeBuiltin, SomeBuiltinMethod,
 SomeFloat, SomeIterator, SomePBC, SomeNone, SomeTypeOf, s_ImpossibleValue,
 s_Bool, s_None, s_Int, unionof, add_knowntypedata,
-SomeWeakRef, SomeUnicodeString, SomeByteArray)
+SomeWeakRef, SomeUnicodeString, SomeByteArray, SomeOrderedDict)
 from rpython.annotator.bookkeeper import getbookkeeper, immutablevalue
 from rpython.annotator.binaryop import _clone ## XXX where to put this?
 from rpython.annotator.binaryop import _dict_can_only_throw_keyerror
@@ -575,6 +575,13 @@
 pair(self, s_key).delitem()
 method_delitem_with_hash.can_only_throw = _dict_can_only_throw_keyerror
 
+class __extend__(SomeOrderedDict):
+
+def method_move_to_end(self, s_key, s_last):
+assert s_Bool.contains(s_last)
+pair(self, s_key).delitem()
+method_move_to_end.can_only_throw = _dict_can_only_throw_keyerror
+
 @op.contains.register(SomeString)
 @op.contains.register(SomeUnicodeString)
 def contains_String(annotator, string, char):
diff --git a/rpython/rlib/objectmodel.py b/rpython/rlib/objectmodel.py
--- a/rpython/rlib/objectmodel.py
+++ b/rpython/rlib/objectmodel.py
@@ -934,6 +934,24 @@
 return
 d.delitem_with_hash(key, h)
 
+def _untranslated_move_to_end(d, key, last):
+"NOT_RPYTHON"
+value = d.pop(key)
+if last:
+d[key] = value
+else:
+items = d.items()
+d.clear()
+d[key] = value
+d.update(items)
+
+@specialize.call_location()
+def move_to_end(d, key, last=True):
+if not we_are_translated():
+_untranslated_move_to_end(d, key, last)
+return
+d.move_to_end(key, last)
+
 # 
 
 def import_from_mixin(M, special_methods=['__init__', '__del__']):
diff --git a/rpython/rlib/test/test_objectmodel.py 
b/rpython/rlib/test/test_objectmodel.py
--- a/rpython/rlib/test/test_objectmodel.py
+++ b/rpython/rlib/test/test_objectmodel.py
@@ -7,7 +7,7 @@
 resizelist_hint, is_annotation_constant, always_inline, NOT_CONSTANT,
 iterkeys_with_hash, iteritems_with_hash, contains_with_hash,
 setitem_with_hash, getitem_with_hash, delitem_with_hash, import_from_mixin,
-fetch_translated_config, try_inline)
+fetch_translated_config, try_inline, move_to_end)
 from rpython.translator.translator import TranslationContext, graphof
 from rpython.rtyper.test.tool import BaseRtypingTest
 from rpython.rtyper.test.test_llinterp import interpret
@@ -679,6 +679,16 @@
 assert f(29) == 0
 interpret(f, [27])
 
+def test_rordereddict_move_to_end():
+d = OrderedDict()
+d['key1'] = 'val1'
+d['key2'] = 'val2'
+d['key3'] = 'val3'
+move_to_end(d, 'key1')
+assert d.items() == [('key2', 'val2'), ('key3', 'val3'), ('key1', 'val1')]
+move_to_end(d, 'key1', last=False)
+assert d.items() == [('key1', 'val1'), ('key2', 'val2'), ('key3', 'val3')]
+
 def test_import_from_mixin():
 class M:# old-style
 def f(self):
diff --git a/rpython/rtyper/lltypesystem/rordereddict.py 
b/rpython/rtyper/lltypesystem/rordereddict.py
--- a/rpython/rtyper/lltypesystem/rordereddict.py
+++ b/rpython/rtyper/lltypesystem/rordereddict.py
@@ -407,6 +407,15 @@
 hop.exception_is_here()
 hop.gendirectcall(ll_dict_delitem_with_hash, v_dict, v_key, v_hash)
 
+def rtype_method_move_to_end(self, hop):
+v_dict, v_key, v_last = hop.inputargs(
+self, self.key_repr, lltype.Bool)
+if not self.custom_eq_hash:
+hop.has_implicit_exception(KeyError)  # record that we know about 
it
+hop.exception_is_here()
+hop.gendirectcall(ll_dict_move_to_end, v_dict, v_key, v_last)
+
+
 class __extend__(pairtype(OrderedDictRepr, rmodel.Repr)):
 
 def rtype_getitem((r_dict, r_key), hop):
@@ -542,16 +551,18 @@
 ll_assert(False, "ll_call_insert_clean_function(): invalid lookup_fun")
 assert False
 
-def ll_call_delete_by_entry_index(d, hash, i):
+def ll_call_delete_by_entry_index(d, hash, i, replace_with):
+# only called from _ll_dict_del, whose @jit.look_inside_iff
+# condition should control when we get inside here with the jit
 fun = d.lookup_function_no & FUNC_MASK
 if fun == FUNC_BYTE:
-ll_dict_delete_by_entry_index(d, hash, i, TYPE_BYTE)
+ll_dict_delete_by_entry_index(d, hash, i, replace_with, TYPE_BYTE)
 elif fun == FUNC_SHORT:
-ll_dict_delete_by_entry_index(d, hash, i, 

[pypy-commit] pypy vendor/stdlib-3.5: Import stdlib from CPython 3.5.3 (changeset 'v3.5.3')

2017-02-05 Thread arigo
Author: Armin Rigo 
Branch: vendor/stdlib-3.5
Changeset: r89950:a9167602e69c
Date: 2017-02-05 19:12 +0100
http://bitbucket.org/pypy/pypy/changeset/a9167602e69c/

Log:Import stdlib from CPython 3.5.3 (changeset 'v3.5.3')

diff too long, truncating to 2000 out of 24911 lines

diff --git a/lib-python/3/_collections_abc.py b/lib-python/3/_collections_abc.py
--- a/lib-python/3/_collections_abc.py
+++ b/lib-python/3/_collections_abc.py
@@ -29,8 +29,8 @@
 # so that they will pass tests like:
 #   it = iter(somebytearray)
 #   assert isinstance(it, Iterable)
-# Note:  in other implementations, these types many not be distinct
-# and they make have their own implementation specific types that
+# Note:  in other implementations, these types might not be distinct
+# and they may have their own implementation specific types that
 # are not included on this list.
 bytes_iterator = type(iter(b''))
 bytearray_iterator = type(iter(bytearray()))
@@ -41,6 +41,7 @@
 list_iterator = type(iter([]))
 list_reverseiterator = type(iter(reversed([])))
 range_iterator = type(iter(range(0)))
+longrange_iterator = type(iter(range(1 << 1000)))
 set_iterator = type(iter(set()))
 str_iterator = type(iter(""))
 tuple_iterator = type(iter(()))
@@ -234,6 +235,7 @@
 Iterator.register(list_iterator)
 Iterator.register(list_reverseiterator)
 Iterator.register(range_iterator)
+Iterator.register(longrange_iterator)
 Iterator.register(set_iterator)
 Iterator.register(str_iterator)
 Iterator.register(tuple_iterator)
diff --git a/lib-python/3/_pydecimal.py b/lib-python/3/_pydecimal.py
--- a/lib-python/3/_pydecimal.py
+++ b/lib-python/3/_pydecimal.py
@@ -1068,12 +1068,11 @@
 return sign + intpart + fracpart + exp
 
 def to_eng_string(self, context=None):
-"""Convert to engineering-type string.
-
-Engineering notation has an exponent which is a multiple of 3, so there
-are up to 3 digits left of the decimal place.
-
-Same rules for when in exponential and when as a value as in __str__.
+"""Convert to a string, using engineering notation if an exponent is 
needed.
+
+Engineering notation has an exponent which is a multiple of 3.  This
+can leave up to 3 digits to the left of the decimal place and may
+require the addition of either one or two trailing zeros.
 """
 return self.__str__(eng=True, context=context)
 
@@ -4107,7 +4106,7 @@
 >>> context.create_decimal_from_float(3.1415926535897932)
 Traceback (most recent call last):
 ...
-decimal.Inexact
+decimal.Inexact: None
 
 """
 d = Decimal.from_float(f)   # An exact conversion
@@ -5502,9 +5501,29 @@
 return r
 
 def to_eng_string(self, a):
-"""Converts a number to a string, using scientific notation.
+"""Convert to a string, using engineering notation if an exponent is 
needed.
+
+Engineering notation has an exponent which is a multiple of 3.  This
+can leave up to 3 digits to the left of the decimal place and may
+require the addition of either one or two trailing zeros.
 
 The operation is not affected by the context.
+
+>>> ExtendedContext.to_eng_string(Decimal('123E+1'))
+'1.23E+3'
+>>> ExtendedContext.to_eng_string(Decimal('123E+3'))
+'123E+3'
+>>> ExtendedContext.to_eng_string(Decimal('123E-10'))
+'12.3E-9'
+>>> ExtendedContext.to_eng_string(Decimal('-123E-12'))
+'-123E-12'
+>>> ExtendedContext.to_eng_string(Decimal('7E-7'))
+'700E-9'
+>>> ExtendedContext.to_eng_string(Decimal('7E+1'))
+'70'
+>>> ExtendedContext.to_eng_string(Decimal('0E+1'))
+'0.00E+3'
+
 """
 a = _convert_other(a, raiseit=True)
 return a.to_eng_string(context=self)
diff --git a/lib-python/3/_pyio.py b/lib-python/3/_pyio.py
--- a/lib-python/3/_pyio.py
+++ b/lib-python/3/_pyio.py
@@ -276,7 +276,7 @@
 try:
 UnsupportedOperation = io.UnsupportedOperation
 except AttributeError:
-class UnsupportedOperation(ValueError, OSError):
+class UnsupportedOperation(OSError, ValueError):
 pass
 
 
diff --git a/lib-python/3/antigravity.py b/lib-python/3/antigravity.py
--- a/lib-python/3/antigravity.py
+++ b/lib-python/3/antigravity.py
@@ -2,7 +2,7 @@
 import webbrowser
 import hashlib
 
-webbrowser.open("http://xkcd.com/353/;)
+webbrowser.open("https://xkcd.com/353/;)
 
 def geohash(latitude, longitude, datedow):
 '''Compute geohash() using the Munroe algorithm.
diff --git a/lib-python/3/asyncio/base_events.py 
b/lib-python/3/asyncio/base_events.py
--- a/lib-python/3/asyncio/base_events.py
+++ b/lib-python/3/asyncio/base_events.py
@@ -13,7 +13,6 @@
 to modify the meaning of the API call itself.
 """
 
-
 import collections
 import concurrent.futures
 import heapq
@@ -28,6 +27,7 @@
 import traceback
 import sys
 import warnings
+import 

[pypy-commit] pypy default: PyOS_AfterFork()

2017-02-05 Thread arigo
Author: Armin Rigo 
Branch: 
Changeset: r89948:1d2ae5c36cef
Date: 2017-02-05 19:03 +0100
http://bitbucket.org/pypy/pypy/changeset/1d2ae5c36cef/

Log:PyOS_AfterFork()

diff --git a/pypy/module/cpyext/pystate.py b/pypy/module/cpyext/pystate.py
--- a/pypy/module/cpyext/pystate.py
+++ b/pypy/module/cpyext/pystate.py
@@ -1,6 +1,7 @@
 from pypy.module.cpyext.api import (
 cpython_api, generic_cpy_call, CANNOT_FAIL, CConfig, cpython_struct)
 from pypy.module.cpyext.pyobject import PyObject, Py_DecRef, make_ref, from_ref
+from pypy.interpreter.error import OperationError
 from rpython.rtyper.lltypesystem import rffi, lltype
 from rpython.rlib import rthread
 from rpython.rlib.objectmodel import we_are_translated
@@ -313,3 +314,16 @@
 be held.  The thread state must have been reset with a previous call to
 PyThreadState_Clear()."""
 
+@cpython_api([], lltype.Void)
+def PyOS_AfterFork(space):
+"""Function to update some internal state after a process fork; this 
should be
+called in the new process if the Python interpreter will continue to be 
used.
+If a new executable is loaded into the new process, this function does not 
need
+to be called."""
+if not space.config.translation.thread:
+return
+from pypy.module.thread import os_thread
+try:
+os_thread.reinit_threads(space)
+except OperationError as e:
+e.write_unraisable(space, "PyOS_AfterFork()")
diff --git a/pypy/module/cpyext/stubs.py b/pypy/module/cpyext/stubs.py
--- a/pypy/module/cpyext/stubs.py
+++ b/pypy/module/cpyext/stubs.py
@@ -1515,14 +1515,6 @@
 one of the strings '' or '???'."""
 raise NotImplementedError
 
-@cpython_api([], lltype.Void)
-def PyOS_AfterFork(space):
-"""Function to update some internal state after a process fork; this 
should be
-called in the new process if the Python interpreter will continue to be 
used.
-If a new executable is loaded into the new process, this function does not 
need
-to be called."""
-raise NotImplementedError
-
 @cpython_api([], rffi.INT_real, error=CANNOT_FAIL)
 def PyOS_CheckStack(space):
 """Return true when the interpreter runs out of stack space.  This is a 
reliable
___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit


[pypy-commit] pypy py3.5: hg merge default

2017-02-05 Thread arigo
Author: Armin Rigo 
Branch: py3.5
Changeset: r89949:9ba6ab77fd29
Date: 2017-02-05 19:05 +0100
http://bitbucket.org/pypy/pypy/changeset/9ba6ab77fd29/

Log:hg merge default

diff --git a/pypy/module/cpyext/pystate.py b/pypy/module/cpyext/pystate.py
--- a/pypy/module/cpyext/pystate.py
+++ b/pypy/module/cpyext/pystate.py
@@ -1,6 +1,7 @@
 from pypy.module.cpyext.api import (
 cpython_api, generic_cpy_call, CANNOT_FAIL, CConfig, cpython_struct)
 from pypy.module.cpyext.pyobject import PyObject, Py_DecRef, make_ref, from_ref
+from pypy.interpreter.error import OperationError
 from rpython.rtyper.lltypesystem import rffi, lltype
 from rpython.rlib import rthread
 from rpython.rlib.objectmodel import we_are_translated
@@ -317,3 +318,16 @@
 be held.  The thread state must have been reset with a previous call to
 PyThreadState_Clear()."""
 
+@cpython_api([], lltype.Void)
+def PyOS_AfterFork(space):
+"""Function to update some internal state after a process fork; this 
should be
+called in the new process if the Python interpreter will continue to be 
used.
+If a new executable is loaded into the new process, this function does not 
need
+to be called."""
+if not space.config.translation.thread:
+return
+from pypy.module.thread import os_thread
+try:
+os_thread.reinit_threads(space)
+except OperationError as e:
+e.write_unraisable(space, "PyOS_AfterFork()")
diff --git a/pypy/module/cpyext/stubs.py b/pypy/module/cpyext/stubs.py
--- a/pypy/module/cpyext/stubs.py
+++ b/pypy/module/cpyext/stubs.py
@@ -1468,14 +1468,6 @@
 one of the strings '' or '???'."""
 raise NotImplementedError
 
-@cpython_api([], lltype.Void)
-def PyOS_AfterFork(space):
-"""Function to update some internal state after a process fork; this 
should be
-called in the new process if the Python interpreter will continue to be 
used.
-If a new executable is loaded into the new process, this function does not 
need
-to be called."""
-raise NotImplementedError
-
 @cpython_api([], rffi.INT_real, error=CANNOT_FAIL)
 def PyOS_CheckStack(space):
 """Return true when the interpreter runs out of stack space.  This is a 
reliable
___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit


[pypy-commit] pypy py3.5: PyCoro_CheckExact()

2017-02-05 Thread arigo
Author: Armin Rigo 
Branch: py3.5
Changeset: r89946:1368d86f0ce9
Date: 2017-02-05 18:00 +0100
http://bitbucket.org/pypy/pypy/changeset/1368d86f0ce9/

Log:PyCoro_CheckExact()

diff --git a/pypy/module/cpyext/genobject.py b/pypy/module/cpyext/genobject.py
--- a/pypy/module/cpyext/genobject.py
+++ b/pypy/module/cpyext/genobject.py
@@ -1,5 +1,7 @@
-from pypy.interpreter.generator import GeneratorIterator
+from pypy.interpreter.generator import GeneratorIterator, Coroutine
 from pypy.module.cpyext.api import build_type_checkers
 
 
 PyGen_Check, PyGen_CheckExact = build_type_checkers("Gen", GeneratorIterator)
+
+_, PyCoro_CheckExact = build_type_checkers("Coro", Coroutine)
diff --git a/pypy/module/cpyext/test/test_genobject.py 
b/pypy/module/cpyext/test/test_genobject.py
--- a/pypy/module/cpyext/test/test_genobject.py
+++ b/pypy/module/cpyext/test/test_genobject.py
@@ -1,5 +1,6 @@
 from pypy.module.cpyext.test.test_api import BaseApiTest
 from pypy.module.cpyext.genobject import PyGen_Check, PyGen_CheckExact
+from pypy.module.cpyext.genobject import PyCoro_CheckExact
 
 
 class TestGenObject(BaseApiTest):
@@ -11,5 +12,16 @@
 """)
 assert PyGen_Check(space, w_geniter)
 assert PyGen_CheckExact(space, w_geniter)
+assert not PyCoro_CheckExact(space, w_geniter)
 assert not PyGen_Check(space, space.wrap(2))
 assert not PyGen_CheckExact(space, space.wrap("b"))
+assert not PyCoro_CheckExact(space, space.wrap([]))
+
+w_coroutine = space.appexec([], """():
+async def f():
+pass
+return f()
+""")
+assert not PyGen_Check(space, w_coroutine)
+assert not PyGen_CheckExact(space, w_coroutine)
+assert PyCoro_CheckExact(space, w_coroutine)
___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit


[pypy-commit] pypy buffer-cleanup: kill buffer_w_ex()

2017-02-05 Thread rlamy
Author: Ronan Lamy 
Branch: buffer-cleanup
Changeset: r89947:d57c072db0e5
Date: 2017-02-05 17:02 +
http://bitbucket.org/pypy/pypy/changeset/d57c072db0e5/

Log:kill buffer_w_ex()

diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -25,15 +25,6 @@
   reds=['items', 'w_iterator'])
 
 
-@specialize.memo()
-def _does_override_buffer_w(type):
-return type.buffer_w != W_Root.buffer_w
-
-@specialize.memo()
-def _does_override_buffer_w_ex(type):
-return type.buffer_w_ex != W_Root.buffer_w_ex
-
-
 class W_Root(object):
 """This is the abstract root class of all wrapped objects that live
 in a 'normal' object space like StdObjSpace."""
@@ -223,15 +214,8 @@
 return None
 
 def buffer_w(self, space, flags):
-if _does_override_buffer_w_ex(self.__class__):
-return self.buffer_w_ex(space, flags)[0]
 return self.__buffer_w(space, flags).buffer_w(space, flags)
 
-def buffer_w_ex(self, space, flags):
-if _does_override_buffer_w(self.__class__):
-return self.buffer_w(space, flags), 'B', 1
-return self.__buffer_w(space, flags).buffer_w_ex(space, flags)
-
 def __buffer_w(self, space, flags):
 if flags & space.BUF_WRITABLE:
 w_impl = space.lookup(self, '__wbuffer__')
@@ -1469,15 +1453,6 @@
 raise oefmt(self.w_TypeError,
 "'%T' does not support the buffer interface", w_obj)
 
-def buffer_w_ex(self, w_obj, flags):
-# New buffer interface, returns a buffer based on flags 
(PyObject_GetBuffer)
-# Returns extra information: (buffer, typecode, itemsize)
-try:
-return w_obj.buffer_w_ex(self, flags)
-except BufferInterfaceNotFound:
-raise oefmt(self.w_TypeError,
-"'%T' does not support the buffer interface", w_obj)
-
 def readbuf_w(self, w_obj):
 # Old buffer interface, returns a readonly buffer 
(PyObject_AsReadBuffer)
 try:
diff --git a/pypy/module/_rawffi/array.py b/pypy/module/_rawffi/array.py
--- a/pypy/module/_rawffi/array.py
+++ b/pypy/module/_rawffi/array.py
@@ -189,10 +189,6 @@
 for i in range(len(value)):
 ll_buffer[start + i] = value[i]
 
-def buffer_w_ex(self, space, flags):
-buf = self.buffer_w(space, flags)
-return buf, buf.getformat(), buf.getitemsize()
-
 
 W_ArrayInstance.typedef = TypeDef(
 'ArrayInstance',
diff --git a/pypy/module/array/interp_array.py 
b/pypy/module/array/interp_array.py
--- a/pypy/module/array/interp_array.py
+++ b/pypy/module/array/interp_array.py
@@ -259,10 +259,6 @@
 def buffer_w(self, space, flags):
 return ArrayBuffer(self, False)
 
-def buffer_w_ex(self, space, flags):
-buf = self.buffer_w(space, flags)
-return buf, buf.getformat(), buf.getitemsize()
-
 def descr_append(self, space, w_x):
 """ append(x)
 
diff --git a/pypy/objspace/std/memoryobject.py 
b/pypy/objspace/std/memoryobject.py
--- a/pypy/objspace/std/memoryobject.py
+++ b/pypy/objspace/std/memoryobject.py
@@ -74,17 +74,18 @@
 def setformat(self, value):
 self.format = value
 
-def buffer_w_ex(self, space, flags):
+def buffer_w(self, space, flags):
 self._check_released(space)
 space.check_buf_flags(flags, self.buf.readonly)
-return self.buf, self.getformat(), self.itemsize
+return self.buf
 
 @staticmethod
 def descr_new_memoryview(space, w_subtype, w_object):
 if isinstance(w_object, W_MemoryView):
 w_object._check_released(space)
 return W_MemoryView.copy(w_object)
-return W_MemoryView(*space.buffer_w_ex(w_object, space.BUF_FULL_RO))
+buf = space.buffer_w(w_object, space.BUF_FULL_RO)
+return W_MemoryView(buf, buf.getformat(), buf.getitemsize())
 
 def _make_descr__cmp(name):
 def descr__cmp(self, space, w_other):
diff --git a/pypy/objspace/std/test/test_memoryobject.py 
b/pypy/objspace/std/test/test_memoryobject.py
--- a/pypy/objspace/std/test/test_memoryobject.py
+++ b/pypy/objspace/std/test/test_memoryobject.py
@@ -345,9 +345,6 @@
 return MockBuffer(space, self.w_list, self.w_dim, self.w_fmt, \
   self.w_size, self.w_strides, self.w_shape)
 
-def buffer_w_ex(self, space, flags):
-return self.buffer_w(space, flags), space.str_w(self.w_fmt), 
space.int_w(self.w_size)
-
 W_MockArray.typedef = TypeDef("MockArray",
 __new__ = interp2app(W_MockArray.descr_new),
 )
___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit


[pypy-commit] pypy py3.5: hg merge default

2017-02-05 Thread arigo
Author: Armin Rigo 
Branch: py3.5
Changeset: r89945:6a45f8963c90
Date: 2017-02-05 17:55 +0100
http://bitbucket.org/pypy/pypy/changeset/6a45f8963c90/

Log:hg merge default

diff --git a/lib_pypy/cffi/api.py b/lib_pypy/cffi/api.py
--- a/lib_pypy/cffi/api.py
+++ b/lib_pypy/cffi/api.py
@@ -93,6 +93,7 @@
 # ctypes backend: attach these constants to the instance
 self.NULL = self.cast(self.BVoidP, 0)
 self.CData, self.CType = backend._get_types()
+self.buffer = backend.buffer
 
 def cdef(self, csource, override=False, packed=False):
 """Parse the given C source.  This registers all declared functions,
@@ -316,18 +317,18 @@
 """
 return self._backend.unpack(cdata, length)
 
-def buffer(self, cdata, size=-1):
-"""Return a read-write buffer object that references the raw C data
-pointed to by the given 'cdata'.  The 'cdata' must be a pointer or
-an array.  Can be passed to functions expecting a buffer, or directly
-manipulated with:
-
-buf[:]  get a copy of it in a regular string, or
-buf[idx]as a single character
-buf[:] = ...
-buf[idx] = ...  change the content
-"""
-return self._backend.buffer(cdata, size)
+   #def buffer(self, cdata, size=-1):
+   #"""Return a read-write buffer object that references the raw C data
+   #pointed to by the given 'cdata'.  The 'cdata' must be a pointer or
+   #an array.  Can be passed to functions expecting a buffer, or directly
+   #manipulated with:
+   #
+   #buf[:]  get a copy of it in a regular string, or
+   #buf[idx]as a single character
+   #buf[:] = ...
+   #buf[idx] = ...  change the content
+   #"""
+   #note that 'buffer' is a type, set on this instance by __init__
 
 def from_buffer(self, python_buffer):
 """Return a  that points to the data of the
@@ -593,11 +594,15 @@
 ensure('extra_link_args', '/MANIFEST')
 
 def set_source(self, module_name, source, source_extension='.c', **kwds):
+import os
 if hasattr(self, '_assigned_source'):
 raise ValueError("set_source() cannot be called several times "
  "per ffi object")
 if not isinstance(module_name, basestring):
 raise TypeError("'module_name' must be a string")
+if os.sep in module_name or (os.altsep and os.altsep in module_name):
+raise ValueError("'module_name' must not contain '/': use a dotted 
"
+ "name to make a 'package.module' location")
 self._assigned_source = (str(module_name), source,
  source_extension, kwds)
 
diff --git a/pypy/module/_cffi_backend/__init__.py 
b/pypy/module/_cffi_backend/__init__.py
--- a/pypy/module/_cffi_backend/__init__.py
+++ b/pypy/module/_cffi_backend/__init__.py
@@ -50,7 +50,7 @@
 
 'string': 'func.string',
 'unpack': 'func.unpack',
-'buffer': 'cbuffer.buffer',
+'buffer': 'cbuffer.MiniBuffer',
 'memmove': 'func.memmove',
 
 'get_errno': 'cerrno.get_errno',
diff --git a/pypy/module/_cffi_backend/cbuffer.py 
b/pypy/module/_cffi_backend/cbuffer.py
--- a/pypy/module/_cffi_backend/cbuffer.py
+++ b/pypy/module/_cffi_backend/cbuffer.py
@@ -75,18 +75,8 @@
 self.buffer.setslice(start, value.as_str())
 
 
-MiniBuffer.typedef = TypeDef(
-"_cffi_backend.buffer",
-__len__ = interp2app(MiniBuffer.descr_len),
-__getitem__ = interp2app(MiniBuffer.descr_getitem),
-__setitem__ = interp2app(MiniBuffer.descr_setitem),
-__weakref__ = make_weakref_descr(MiniBuffer),
-)
-MiniBuffer.typedef.acceptable_as_base_class = False
-
-
 @unwrap_spec(w_cdata=cdataobj.W_CData, size=int)
-def buffer(space, w_cdata, size=-1):
+def MiniBuffer___new__(space, w_subtype, w_cdata, size=-1):
 ctype = w_cdata.ctype
 if isinstance(ctype, ctypeptr.W_CTypePointer):
 if size < 0:
@@ -107,3 +97,24 @@
 "don't know the size pointed to by '%s'", ctype.name)
 ptr = w_cdata.unsafe_escaping_ptr()# w_cdata kept alive by MiniBuffer()
 return space.wrap(MiniBuffer(LLBuffer(ptr, size), w_cdata))
+
+MiniBuffer.typedef = TypeDef(
+"_cffi_backend.buffer",
+__new__ = interp2app(MiniBuffer___new__),
+__len__ = interp2app(MiniBuffer.descr_len),
+__getitem__ = interp2app(MiniBuffer.descr_getitem),
+__setitem__ = interp2app(MiniBuffer.descr_setitem),
+__weakref__ = make_weakref_descr(MiniBuffer),
+__doc__ = """ffi.buffer(cdata[, byte_size]):
+Return a read-write buffer object that references the raw C data
+pointed to by the given 'cdata'.  The 'cdata' must be a pointer or an
+array.  Can be passed to functions expecting a buffer, or directly
+manipulated with:
+
+buf[:]  get a copy of it in a regular string, or

[pypy-commit] pypy default: PyGen_Check(), PyGen_CheckExact()

2017-02-05 Thread arigo
Author: Armin Rigo 
Branch: 
Changeset: r89944:7a5c63c2feec
Date: 2017-02-05 17:52 +0100
http://bitbucket.org/pypy/pypy/changeset/7a5c63c2feec/

Log:PyGen_Check(), PyGen_CheckExact()

diff --git a/pypy/module/cpyext/genobject.py b/pypy/module/cpyext/genobject.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/genobject.py
@@ -0,0 +1,5 @@
+from pypy.interpreter.generator import GeneratorIterator
+from pypy.module.cpyext.api import build_type_checkers
+
+
+PyGen_Check, PyGen_CheckExact = build_type_checkers("Gen", GeneratorIterator)
diff --git a/pypy/module/cpyext/stubs.py b/pypy/module/cpyext/stubs.py
--- a/pypy/module/cpyext/stubs.py
+++ b/pypy/module/cpyext/stubs.py
@@ -695,17 +695,6 @@
 extension modules."""
 raise NotImplementedError
 
-@cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL)
-def PyGen_Check(space, ob):
-"""Return true if ob is a generator object; ob must not be NULL."""
-raise NotImplementedError
-
-@cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL)
-def PyGen_CheckExact(space, ob):
-"""Return true if ob's type is PyGen_Type is a generator object; ob must 
not
-be NULL."""
-raise NotImplementedError
-
 @cpython_api([PyFrameObject], PyObject)
 def PyGen_New(space, frame):
 """Create and return a new generator object based on the frame object. A
diff --git a/pypy/module/cpyext/test/test_genobject.py 
b/pypy/module/cpyext/test/test_genobject.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/test/test_genobject.py
@@ -0,0 +1,15 @@
+from pypy.module.cpyext.test.test_api import BaseApiTest
+from pypy.module.cpyext.genobject import PyGen_Check, PyGen_CheckExact
+
+
+class TestGenObject(BaseApiTest):
+def test_genobject(self, space):
+w_geniter = space.appexec([], """():
+def f():
+yield 42
+return f()
+""")
+assert PyGen_Check(space, w_geniter)
+assert PyGen_CheckExact(space, w_geniter)
+assert not PyGen_Check(space, space.wrap(2))
+assert not PyGen_CheckExact(space, space.wrap("b"))
___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit


[pypy-commit] pypy py3.5: PyErr_WarnFormat

2017-02-05 Thread arigo
Author: Armin Rigo 
Branch: py3.5
Changeset: r89943:386cfc419af7
Date: 2017-02-05 17:44 +0100
http://bitbucket.org/pypy/pypy/changeset/386cfc419af7/

Log:PyErr_WarnFormat

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
@@ -571,6 +571,7 @@
 '_Py_BuildValue_SizeT', '_Py_VaBuildValue_SizeT',
 
 'PyErr_Format', 'PyErr_NewException', 'PyErr_NewExceptionWithDoc',
+'PyErr_WarnFormat',
 'PySys_WriteStdout', 'PySys_WriteStderr',
 
 'PyEval_CallFunction', 'PyEval_CallMethod', 'PyObject_CallFunction',
@@ -1321,6 +1322,7 @@
  source_dir / "bytesobject.c",
  source_dir / "complexobject.c",
  source_dir / "import.c",
+ source_dir / "_warnings.c",
  ]
 
 def build_eci(code, use_micronumpy=False, translating=False):
diff --git a/pypy/module/cpyext/include/warnings.h 
b/pypy/module/cpyext/include/warnings.h
--- a/pypy/module/cpyext/include/warnings.h
+++ b/pypy/module/cpyext/include/warnings.h
@@ -6,6 +6,9 @@
 
 #define PyErr_WarnPy3k(msg, stacklevel) 0
 
+PyAPI_FUNC(int) PyErr_WarnFormat(PyObject *category, Py_ssize_t stack_level,
+ const char *format, ...);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/pypy/module/cpyext/src/_warnings.c 
b/pypy/module/cpyext/src/_warnings.c
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/src/_warnings.c
@@ -0,0 +1,25 @@
+#include 
+
+int
+PyErr_WarnFormat(PyObject *category, Py_ssize_t stack_level,
+ const char *format, ...)
+{
+int ret;
+PyObject *message;
+va_list vargs;
+
+#ifdef HAVE_STDARG_PROTOTYPES
+va_start(vargs, format);
+#else
+va_start(vargs);
+#endif
+message = PyUnicode_FromFormatV(format, vargs);
+if (message != NULL) {
+ret = PyErr_WarnEx(category, PyUnicode_AsUTF8(message), stack_level);
+Py_DECREF(message);
+}
+else
+ret = -1;
+va_end(vargs);
+return ret;
+}
diff --git a/pypy/module/cpyext/stubs.py b/pypy/module/cpyext/stubs.py
--- a/pypy/module/cpyext/stubs.py
+++ b/pypy/module/cpyext/stubs.py
@@ -405,14 +405,6 @@
 (sys.getfilesystemencoding())."""
 raise NotImplementedError
 
-@cpython_api([PyObject, Py_ssize_t, rffi.CCHARP, ], rffi.INT_real, error=-1)
-def PyErr_WarnFormat(space, category, stack_level, format, ):
-"""Function similar to PyErr_WarnEx(), but use
-PyUnicode_FromFormat() to format the warning message.  format is
-an ASCII-encoded string.
-"""
-raise NotImplementedError
-
 
 @cpython_api([rffi.INT_real], rffi.INT_real, error=-1)
 def PySignal_SetWakeupFd(space, fd):
diff --git a/pypy/module/cpyext/test/test_pyerrors.py 
b/pypy/module/cpyext/test/test_pyerrors.py
--- a/pypy/module/cpyext/test/test_pyerrors.py
+++ b/pypy/module/cpyext/test/test_pyerrors.py
@@ -428,3 +428,18 @@
 assert orig_exc_info == reset_sys_exc_info
 assert new_exc_info == (new_exc.__class__, new_exc, None)
 assert new_exc_info == new_sys_exc_info
+
+def test_PyErr_WarnFormat(self):
+import warnings
+
+module = self.import_extension('foo', [
+("test", "METH_NOARGS",
+ '''
+ PyErr_WarnFormat(PyExc_UserWarning, 1, "foo %d bar", 42);
+ Py_RETURN_NONE;
+ '''),
+])
+with warnings.catch_warnings(record=True) as l:
+module.test()
+assert len(l) == 1
+assert "foo 42 bar" in str(l[0])
___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit


[pypy-commit] pypy default: silence a warning

2017-02-05 Thread arigo
Author: Armin Rigo 
Branch: 
Changeset: r89941:587b40019180
Date: 2017-02-05 17:21 +0100
http://bitbucket.org/pypy/pypy/changeset/587b40019180/

Log:silence a warning

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
@@ -1069,7 +1069,8 @@
 struct PyPyAPI {
 %(members)s
 } _pypyAPI;
-RPY_EXTERN struct PyPyAPI* pypyAPI = &_pypyAPI;
+RPY_EXTERN struct PyPyAPI* pypyAPI;
+struct PyPyAPI* pypyAPI = &_pypyAPI;
 """ % dict(members=structmembers)
 
 global_objects = []
___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit


[pypy-commit] pypy buffer-cleanup: Add W_ArrayBase.buffer_w()

2017-02-05 Thread rlamy
Author: Ronan Lamy 
Branch: buffer-cleanup
Changeset: r89942:1ed5b196b55d
Date: 2017-02-05 16:31 +
http://bitbucket.org/pypy/pypy/changeset/1ed5b196b55d/

Log:Add W_ArrayBase.buffer_w()

diff --git a/pypy/module/array/interp_array.py 
b/pypy/module/array/interp_array.py
--- a/pypy/module/array/interp_array.py
+++ b/pypy/module/array/interp_array.py
@@ -256,8 +256,12 @@
 if oldbuffer:
 lltype.free(oldbuffer, flavor='raw')
 
+def buffer_w(self, space, flags):
+return ArrayBuffer(self, False)
+
 def buffer_w_ex(self, space, flags):
-return ArrayBuffer(self, False), self.typecode, self.itemsize
+buf = self.buffer_w(space, flags)
+return buf, buf.getformat(), buf.getitemsize()
 
 def descr_append(self, space, w_x):
 """ append(x)
___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit


[pypy-commit] pypy default: silence a warning

2017-02-05 Thread arigo
Author: Armin Rigo 
Branch: 
Changeset: r89940:c763e1ab0f07
Date: 2017-02-05 17:17 +0100
http://bitbucket.org/pypy/pypy/changeset/c763e1ab0f07/

Log:silence a warning

diff --git a/rpython/rlib/rposix_stat.py b/rpython/rlib/rposix_stat.py
--- a/rpython/rlib/rposix_stat.py
+++ b/rpython/rlib/rposix_stat.py
@@ -602,7 +602,7 @@
 
 if rposix.HAVE_FSTATAT:
 from rpython.rlib.rposix import AT_FDCWD, AT_SYMLINK_NOFOLLOW
-c_fstatat = rffi.llexternal('fstatat',
+c_fstatat = rffi.llexternal('fstatat64' if _LINUX else 'fstatat',
 [rffi.INT, rffi.CCHARP, STAT_STRUCT, rffi.INT], rffi.INT,
 compilation_info=compilation_info,
 save_err=rffi.RFFI_SAVE_ERRNO, macro=True)
___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit


[pypy-commit] pypy buffer-cleanup: Add getformat() and getitemsize() to RawFFIBuffer

2017-02-05 Thread rlamy
Author: Ronan Lamy 
Branch: buffer-cleanup
Changeset: r89939:82e6578296c4
Date: 2017-02-05 16:15 +
http://bitbucket.org/pypy/pypy/changeset/82e6578296c4/

Log:Add getformat() and getitemsize() to RawFFIBuffer

diff --git a/pypy/module/_rawffi/array.py b/pypy/module/_rawffi/array.py
--- a/pypy/module/_rawffi/array.py
+++ b/pypy/module/_rawffi/array.py
@@ -91,6 +91,8 @@
 W_DataInstance.__init__(self, space, memsize, address)
 self.length = length
 self.shape = shape
+self.fmt = shape.itemcode
+self.itemsize = shape.size
 
 def descr_repr(self, space):
 addr = rffi.cast(lltype.Unsigned, self.ll_buffer)
@@ -105,8 +107,7 @@
 raise segfault_exception(space, "setting element of freed array")
 if num >= self.length or num < 0:
 raise OperationError(space.w_IndexError, space.w_None)
-unwrap_value(space, write_ptr, self.ll_buffer, num,
- self.shape.itemcode, w_value)
+unwrap_value(space, write_ptr, self.ll_buffer, num, self.fmt, w_value)
 
 def descr_setitem(self, space, w_index, w_value):
 try:
@@ -123,8 +124,7 @@
 raise segfault_exception(space, "accessing elements of freed 
array")
 if num >= self.length or num < 0:
 raise OperationError(space.w_IndexError, space.w_None)
-return wrap_value(space, read_ptr, self.ll_buffer, num,
-  self.shape.itemcode)
+return wrap_value(space, read_ptr, self.ll_buffer, num, self.fmt)
 
 def descr_getitem(self, space, w_index):
 try:
@@ -141,19 +141,16 @@
 
 @unwrap_spec(num=int)
 def descr_itemaddress(self, space, num):
-itemsize = self.shape.size
-ptr = rffi.ptradd(self.ll_buffer, itemsize * num)
+ptr = rffi.ptradd(self.ll_buffer, self.itemsize * num)
 return space.wrap(rffi.cast(lltype.Unsigned, ptr))
 
 def getrawsize(self):
-itemsize = self.shape.size
-return itemsize * self.length
+return self.itemsize * self.length
 
 def decodeslice(self, space, w_slice):
 if not space.isinstance_w(w_slice, space.w_slice):
 raise oefmt(space.w_TypeError, "index must be int or slice")
-letter = self.shape.itemcode
-if letter != 'c':
+if self.fmt != 'c':
 raise oefmt(space.w_TypeError, "only 'c' arrays support slicing")
 w_start = space.getattr(w_slice, space.wrap('start'))
 w_stop = space.getattr(w_slice, space.wrap('stop'))
@@ -193,7 +190,8 @@
 ll_buffer[start + i] = value[i]
 
 def buffer_w_ex(self, space, flags):
-return self.buffer_w(space, flags), self.shape.itemcode, 
self.shape.size
+buf = self.buffer_w(space, flags)
+return buf, buf.getformat(), buf.getitemsize()
 
 
 W_ArrayInstance.typedef = TypeDef(
diff --git a/pypy/module/_rawffi/buffer.py b/pypy/module/_rawffi/buffer.py
--- a/pypy/module/_rawffi/buffer.py
+++ b/pypy/module/_rawffi/buffer.py
@@ -14,6 +14,12 @@
 def getlength(self):
 return self.datainstance.getrawsize()
 
+def getformat(self):
+return self.datainstance.fmt
+
+def getitemsize(self):
+return self.datainstance.itemsize
+
 def getitem(self, index):
 ll_buffer = self.datainstance.ll_buffer
 return ll_buffer[index]
diff --git a/pypy/module/_rawffi/interp_rawffi.py 
b/pypy/module/_rawffi/interp_rawffi.py
--- a/pypy/module/_rawffi/interp_rawffi.py
+++ b/pypy/module/_rawffi/interp_rawffi.py
@@ -337,6 +337,8 @@
 
 
 class W_DataInstance(W_Root):
+fmt = 'B'
+itemsize = 1
 def __init__(self, space, size, address=r_uint(0)):
 if address:
 self.ll_buffer = rffi.cast(rffi.VOIDP, address)
___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit


[pypy-commit] pypy py3.5: Normalize the PyMem_Xxx functions and macros to CPython 3.5's situation

2017-02-05 Thread arigo
Author: Armin Rigo 
Branch: py3.5
Changeset: r89938:319cd6335518
Date: 2017-02-05 17:13 +0100
http://bitbucket.org/pypy/pypy/changeset/319cd6335518/

Log:Normalize the PyMem_Xxx functions and macros to CPython 3.5's
situation

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
@@ -612,6 +612,9 @@
 'Py_FrozenFlag', 'Py_TabcheckFlag', 'Py_UnicodeFlag', 
'Py_IgnoreEnvironmentFlag',
 'Py_DivisionWarningFlag', 'Py_DontWriteBytecodeFlag', 
'Py_NoUserSiteDirectory',
 '_Py_QnewFlag', 'Py_Py3kWarningFlag', 'Py_HashRandomizationFlag', 
'_Py_PackageContext',
+
+'PyMem_RawMalloc', 'PyMem_RawCalloc', 'PyMem_RawRealloc', 'PyMem_RawFree',
+'PyMem_Malloc', 'PyMem_Calloc', 'PyMem_Realloc', 'PyMem_Free',
 ]
 TYPES = {}
 FORWARD_DECLS = []
diff --git a/pypy/module/cpyext/include/pymem.h 
b/pypy/module/cpyext/include/pymem.h
--- a/pypy/module/cpyext/include/pymem.h
+++ b/pypy/module/cpyext/include/pymem.h
@@ -7,17 +7,22 @@
 extern "C" {
 #endif
 
-#define PyMem_MALLOC(n)malloc((n) ? (n) : 1)
-#define PyMem_REALLOC(p, n)realloc((p), (n) ? (n) : 1)
-#define PyMem_FREE free
+#ifndef Py_LIMITED_API
+PyAPI_FUNC(void *) PyMem_RawMalloc(size_t size);
+PyAPI_FUNC(void *) PyMem_RawCalloc(size_t nelem, size_t elsize);
+PyAPI_FUNC(void *) PyMem_RawRealloc(void *ptr, size_t new_size);
+PyAPI_FUNC(void) PyMem_RawFree(void *ptr);
+#endif
 
-PyAPI_FUNC(void *) PyMem_Malloc(size_t);
-#define PyMem_Free  PyMem_FREE
-#define PyMem_Realloc  PyMem_REALLOC
+PyAPI_FUNC(void *) PyMem_Malloc(size_t size);
+PyAPI_FUNC(void *) PyMem_Calloc(size_t nelem, size_t elsize);
+PyAPI_FUNC(void *) PyMem_Realloc(void *ptr, size_t new_size);
+PyAPI_FUNC(void) PyMem_Free(void *ptr);
 
-#define PyMem_RawMalloc PyMem_Malloc
-#define PyMem_RawFree PyMem_Free
-#define PyMem_RawRealloc PyMem_Realloc
+#define PyMem_MALLOC(n) PyMem_Malloc(n)
+#define PyMem_REALLOC(p, n) PyMem_Realloc(p, n)
+#define PyMem_FREE(p)   PyMem_Free(p)
+
 
 /*
  * Type-oriented memory interface
diff --git a/pypy/module/cpyext/src/pymem.c b/pypy/module/cpyext/src/pymem.c
--- a/pypy/module/cpyext/src/pymem.c
+++ b/pypy/module/cpyext/src/pymem.c
@@ -1,6 +1,86 @@
 #include 
 
-void * PyMem_Malloc(size_t n)
+void *
+PyMem_RawMalloc(size_t size)
 {
-return malloc((n) ? (n) : 1);
+/*
+ * Limit ourselves to PY_SSIZE_T_MAX bytes to prevent security holes.
+ * Most python internals blindly use a signed Py_ssize_t to track
+ * things without checking for overflows or negatives.
+ * As size_t is unsigned, checking for size < 0 is not required.
+ */
+if (size > (size_t)PY_SSIZE_T_MAX)
+return NULL;
+if (size == 0)
+size = 1;
+return malloc(size);
 }
+
+void *
+PyMem_RawCalloc(size_t nelem, size_t elsize)
+{
+/* see PyMem_RawMalloc() */
+if (elsize != 0 && nelem > (size_t)PY_SSIZE_T_MAX / elsize)
+return NULL;
+/* PyMem_RawCalloc(0, 0) means calloc(1, 1). Some systems would return NULL
+   for calloc(0, 0), which would be treated as an error. Some platforms
+   would return a pointer with no memory behind it, which would break
+   pymalloc.  To solve these problems, allocate an extra byte. */
+if (nelem == 0 || elsize == 0) {
+nelem = 1;
+elsize = 1;
+}
+return calloc(nelem, elsize);
+}
+
+void*
+PyMem_RawRealloc(void *ptr, size_t size)
+{
+/* see PyMem_RawMalloc() */
+if (size > (size_t)PY_SSIZE_T_MAX)
+return NULL;
+if (size == 0)
+size = 1;
+return realloc(ptr, size);
+}
+
+void PyMem_RawFree(void *ptr)
+{
+free(ptr);
+}
+
+
+/* the PyMem_Xxx functions are the same as PyMem_RawXxx in PyPy, for now */
+void *PyMem_Malloc(size_t size)
+{
+if (size > (size_t)PY_SSIZE_T_MAX)
+return NULL;
+if (size == 0)
+size = 1;
+return malloc(size);
+}
+
+void *PyMem_Calloc(size_t nelem, size_t elsize)
+{
+if (elsize != 0 && nelem > (size_t)PY_SSIZE_T_MAX / elsize)
+return NULL;
+if (nelem == 0 || elsize == 0) {
+nelem = 1;
+elsize = 1;
+}
+return calloc(nelem, elsize);
+}
+
+void* PyMem_Realloc(void *ptr, size_t size)
+{
+if (size > (size_t)PY_SSIZE_T_MAX)
+return NULL;
+if (size == 0)
+size = 1;
+return realloc(ptr, size);
+}
+
+void PyMem_Free(void *ptr)
+{
+free(ptr);
+}
diff --git a/pypy/module/cpyext/test/test_pymem.py 
b/pypy/module/cpyext/test/test_pymem.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/test/test_pymem.py
@@ -0,0 +1,34 @@
+from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
+
+
+class AppTestPyMem(AppTestCpythonExtensionBase):
+def test_pymem_alloc(self):
+module = self.import_extension('foo', [
+("test", "METH_NOARGS",
+ """
+int *a, *b;
+a = PyMem_RawCalloc(4, 50);
+ 

[pypy-commit] extradoc extradoc: done

2017-02-05 Thread arigo
Author: Armin Rigo 
Branch: extradoc
Changeset: r5773:811543e4ff04
Date: 2017-02-05 15:33 +0100
http://bitbucket.org/pypy/extradoc/changeset/811543e4ff04/

Log:done

diff --git a/planning/py3.5/milestone-2-progress.rst 
b/planning/py3.5/milestone-2-progress.rst
--- a/planning/py3.5/milestone-2-progress.rst
+++ b/planning/py3.5/milestone-2-progress.rst
@@ -17,6 +17,7 @@
 * collections.py: ``OrderedDict`` should again be a thin wrapper over
   ``dict``.  The main pain point is ``move_to_end(last=False)``.  See
   https://mail.python.org/pipermail/python-dev/2016-August/145837.html
+  [DONE]
 
 * compare ``dir(posix)`` on py3.5 and cpython 3.5.
 
___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit


[pypy-commit] pypy py3.5: missing import

2017-02-05 Thread arigo
Author: Armin Rigo 
Branch: py3.5
Changeset: r89937:fb91b76b7210
Date: 2017-02-05 11:40 +0100
http://bitbucket.org/pypy/pypy/changeset/fb91b76b7210/

Log:missing import

diff --git a/lib_pypy/_pypy_collections.py b/lib_pypy/_pypy_collections.py
--- a/lib_pypy/_pypy_collections.py
+++ b/lib_pypy/_pypy_collections.py
@@ -1,4 +1,5 @@
 from __pypy__ import reversed_dict, move_to_end
+from _operator import eq as _eq
 from reprlib import recursive_repr as _recursive_repr
 
 class OrderedDict(dict):
___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit


[pypy-commit] pypy.org extradoc: update the values

2017-02-05 Thread arigo
Author: Armin Rigo 
Branch: extradoc
Changeset: r851:f22c38f24a8b
Date: 2017-02-05 11:08 +0100
http://bitbucket.org/pypy/pypy.org/changeset/f22c38f24a8b/

Log:update the values

diff --git a/don1.html b/don1.html
--- a/don1.html
+++ b/don1.html
@@ -15,7 +15,7 @@
 
 

-   $66561 of $105000 (63.4%)
+   $66570 of $105000 (63.4%)


 
@@ -23,7 +23,7 @@
   
   This donation goes towards supporting Python 3 in 
PyPy.
   Current status:
-we have $2391 left
+we have $2399 left
   in the account. Read proposal
   
   
___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit


[pypy-commit] pypy py3.5: hg merge dict-move-to-end

2017-02-05 Thread arigo
Author: Armin Rigo 
Branch: py3.5
Changeset: r89934:5e325b5c62d9
Date: 2017-02-05 08:29 +0100
http://bitbucket.org/pypy/pypy/changeset/5e325b5c62d9/

Log:hg merge dict-move-to-end

diff --git a/pypy/doc/stackless.rst b/pypy/doc/stackless.rst
--- a/pypy/doc/stackless.rst
+++ b/pypy/doc/stackless.rst
@@ -190,7 +190,7 @@
 from GC issues: if the program "forgets" an unfinished greenlet, it will
 always be collected at the next garbage collection.
 
-.. _documentation of the greenlets: http://packages.python.org/greenlet/
+.. _documentation of the greenlets: https://greenlet.readthedocs.io/
 
 
 Unimplemented features
diff --git a/rpython/annotator/unaryop.py b/rpython/annotator/unaryop.py
--- a/rpython/annotator/unaryop.py
+++ b/rpython/annotator/unaryop.py
@@ -14,7 +14,7 @@
 SomeUnicodeCodePoint, SomeInstance, SomeBuiltin, SomeBuiltinMethod,
 SomeFloat, SomeIterator, SomePBC, SomeNone, SomeTypeOf, s_ImpossibleValue,
 s_Bool, s_None, s_Int, unionof, add_knowntypedata,
-SomeWeakRef, SomeUnicodeString, SomeByteArray)
+SomeWeakRef, SomeUnicodeString, SomeByteArray, SomeOrderedDict)
 from rpython.annotator.bookkeeper import getbookkeeper, immutablevalue
 from rpython.annotator.binaryop import _clone ## XXX where to put this?
 from rpython.annotator.binaryop import _dict_can_only_throw_keyerror
@@ -575,6 +575,13 @@
 pair(self, s_key).delitem()
 method_delitem_with_hash.can_only_throw = _dict_can_only_throw_keyerror
 
+class __extend__(SomeOrderedDict):
+
+def method_move_to_end(self, s_key, s_last):
+assert s_Bool.contains(s_last)
+pair(self, s_key).delitem()
+method_move_to_end.can_only_throw = _dict_can_only_throw_keyerror
+
 @op.contains.register(SomeString)
 @op.contains.register(SomeUnicodeString)
 def contains_String(annotator, string, char):
diff --git a/rpython/rlib/objectmodel.py b/rpython/rlib/objectmodel.py
--- a/rpython/rlib/objectmodel.py
+++ b/rpython/rlib/objectmodel.py
@@ -934,6 +934,24 @@
 return
 d.delitem_with_hash(key, h)
 
+def _untranslated_move_to_end(d, key, last):
+"NOT_RPYTHON"
+value = d.pop(key)
+if last:
+d[key] = value
+else:
+items = d.items()
+d.clear()
+d[key] = value
+d.update(items)
+
+@specialize.call_location()
+def move_to_end(d, key, last=True):
+if not we_are_translated():
+_untranslated_move_to_end(d, key, last)
+return
+d.move_to_end(key, last)
+
 # 
 
 def import_from_mixin(M, special_methods=['__init__', '__del__']):
diff --git a/rpython/rlib/test/test_objectmodel.py 
b/rpython/rlib/test/test_objectmodel.py
--- a/rpython/rlib/test/test_objectmodel.py
+++ b/rpython/rlib/test/test_objectmodel.py
@@ -7,7 +7,7 @@
 resizelist_hint, is_annotation_constant, always_inline, NOT_CONSTANT,
 iterkeys_with_hash, iteritems_with_hash, contains_with_hash,
 setitem_with_hash, getitem_with_hash, delitem_with_hash, import_from_mixin,
-fetch_translated_config, try_inline)
+fetch_translated_config, try_inline, move_to_end)
 from rpython.translator.translator import TranslationContext, graphof
 from rpython.rtyper.test.tool import BaseRtypingTest
 from rpython.rtyper.test.test_llinterp import interpret
@@ -679,6 +679,16 @@
 assert f(29) == 0
 interpret(f, [27])
 
+def test_rordereddict_move_to_end():
+d = OrderedDict()
+d['key1'] = 'val1'
+d['key2'] = 'val2'
+d['key3'] = 'val3'
+move_to_end(d, 'key1')
+assert d.items() == [('key2', 'val2'), ('key3', 'val3'), ('key1', 'val1')]
+move_to_end(d, 'key1', last=False)
+assert d.items() == [('key1', 'val1'), ('key2', 'val2'), ('key3', 'val3')]
+
 def test_import_from_mixin():
 class M:# old-style
 def f(self):
diff --git a/rpython/rtyper/lltypesystem/rordereddict.py 
b/rpython/rtyper/lltypesystem/rordereddict.py
--- a/rpython/rtyper/lltypesystem/rordereddict.py
+++ b/rpython/rtyper/lltypesystem/rordereddict.py
@@ -407,6 +407,15 @@
 hop.exception_is_here()
 hop.gendirectcall(ll_dict_delitem_with_hash, v_dict, v_key, v_hash)
 
+def rtype_method_move_to_end(self, hop):
+v_dict, v_key, v_last = hop.inputargs(
+self, self.key_repr, lltype.Bool)
+if not self.custom_eq_hash:
+hop.has_implicit_exception(KeyError)  # record that we know about 
it
+hop.exception_is_here()
+hop.gendirectcall(ll_dict_move_to_end, v_dict, v_key, v_last)
+
+
 class __extend__(pairtype(OrderedDictRepr, rmodel.Repr)):
 
 def rtype_getitem((r_dict, r_key), hop):
@@ -542,16 +551,18 @@
 ll_assert(False, "ll_call_insert_clean_function(): invalid lookup_fun")
 assert False
 
-def ll_call_delete_by_entry_index(d, hash, i):
+def ll_call_delete_by_entry_index(d, hash, i, replace_with):
+# only called from _ll_dict_del, whose @jit.look_inside_iff
+# condition should control when we get 

[pypy-commit] pypy py3.5: PyPy's simplified version of OrderedDict

2017-02-05 Thread arigo
Author: Armin Rigo 
Branch: py3.5
Changeset: r89936:5764bb3f54a2
Date: 2017-02-05 11:08 +0100
http://bitbucket.org/pypy/pypy/changeset/5764bb3f54a2/

Log:PyPy's simplified version of OrderedDict

diff --git a/lib_pypy/_collections.py b/lib_pypy/_collections.py
--- a/lib_pypy/_collections.py
+++ b/lib_pypy/_collections.py
@@ -439,3 +439,8 @@
 return (type(self), (self.default_factory,), None, None,
 iter(self.items()))
 
+
+try:
+from _pypy_collections import OrderedDict
+except ImportError:
+pass
diff --git a/lib_pypy/_pypy_collections.py b/lib_pypy/_pypy_collections.py
new file mode 100644
--- /dev/null
+++ b/lib_pypy/_pypy_collections.py
@@ -0,0 +1,69 @@
+from __pypy__ import reversed_dict, move_to_end
+from reprlib import recursive_repr as _recursive_repr
+
+class OrderedDict(dict):
+'''Dictionary that remembers insertion order.
+
+In PyPy all dicts are ordered anyway.  This is mostly useful as a
+placeholder to mean "this dict must be ordered even on CPython".
+
+Known difference: iterating over an OrderedDict which is being
+concurrently modified raises RuntimeError in PyPy.  In CPython
+instead we get some behavior that appears reasonable in some
+cases but is nonsensical in other cases.  This is officially
+forbidden by the CPython docs, so we forbid it explicitly for now.
+'''
+
+def __reversed__(self):
+return reversed_dict(self)
+
+def popitem(self, last=True):
+'''od.popitem() -> (k, v), return and remove a (key, value) pair.
+Pairs are returned in LIFO order if last is true or FIFO order if 
false.
+
+'''
+if last:
+return dict.popitem(self)
+else:
+it = dict.__iter__(self)
+try:
+k = it.next()
+except StopIteration:
+raise KeyError('dictionary is empty')
+return (k, self.pop(k))
+
+def move_to_end(self, key, last=True):
+'''Move an existing element to the end (or beginning if last==False).
+
+Raises KeyError if the element does not exist.
+When last=True, acts like a fast version of self[key]=self.pop(key).
+
+'''
+return move_to_end(self, key, last)
+
+@_recursive_repr()
+def __repr__(self):
+'od.__repr__() <==> repr(od)'
+if not self:
+return '%s()' % (self.__class__.__name__,)
+return '%s(%r)' % (self.__class__.__name__, list(self.items()))
+
+def __reduce__(self):
+'Return state information for pickling'
+inst_dict = vars(self).copy()
+return self.__class__, (), inst_dict or None, None, iter(self.items())
+
+def copy(self):
+'od.copy() -> a shallow copy of od'
+return self.__class__(self)
+
+def __eq__(self, other):
+'''od.__eq__(y) <==> od==y.  Comparison to another OD is 
order-sensitive
+while comparison to a regular mapping is order-insensitive.
+
+'''
+if isinstance(other, OrderedDict):
+return dict.__eq__(self, other) and all(map(_eq, self, other))
+return dict.__eq__(self, other)
+
+__ne__ = object.__ne__
diff --git a/pypy/module/_collections/__init__.py 
b/pypy/module/_collections/__init__.py
--- a/pypy/module/_collections/__init__.py
+++ b/pypy/module/_collections/__init__.py
@@ -25,3 +25,15 @@
 space = self.space
 space.getattr(self, space.wrap('defaultdict'))  # force importing
 space.delattr(self, space.wrap('__missing__'))
+
+def startup(self, space):
+# OrderedDict is normally present, but in some cases the line
+# "from __pypy__ import reversed_dict, move_to_end" from
+# _pypy_collections.py raises
+space.appexec([space.wrap(self)], """(mod):
+try:
+from _pypy_collections import OrderedDict
+mod.OrderedDict = OrderedDict
+except ImportError:
+pass
+""")
diff --git a/pypy/module/_collections/test/test_ordereddict.py 
b/pypy/module/_collections/test/test_ordereddict.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_collections/test/test_ordereddict.py
@@ -0,0 +1,8 @@
+
+class AppTestBasic:
+spaceconfig = dict(usemodules=['_collections'])
+
+def test_ordereddict_present(self):
+from _collections import OrderedDict
+assert issubclass(OrderedDict, dict)
+assert hasattr(OrderedDict, 'move_to_end')
___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit


[pypy-commit] pypy py3.5: Add __pypy__.move_to_end(), similar to __pypy__.reversed_dict().

2017-02-05 Thread arigo
Author: Armin Rigo 
Branch: py3.5
Changeset: r89935:6974fd5f5c47
Date: 2017-02-05 10:57 +0100
http://bitbucket.org/pypy/pypy/changeset/6974fd5f5c47/

Log:Add __pypy__.move_to_end(), similar to __pypy__.reversed_dict().

diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py
--- a/pypy/module/__pypy__/__init__.py
+++ b/pypy/module/__pypy__/__init__.py
@@ -78,6 +78,7 @@
 'add_memory_pressure'   : 'interp_magic.add_memory_pressure',
 'newdict'   : 'interp_dict.newdict',
 'reversed_dict' : 'interp_dict.reversed_dict',
+'move_to_end'   : 'interp_dict.move_to_end',
 'strategy'  : 'interp_magic.strategy',  # dict,set,list
 'set_debug' : 'interp_magic.set_debug',
 'locals_to_fast': 'interp_magic.locals_to_fast',
diff --git a/pypy/module/__pypy__/interp_dict.py 
b/pypy/module/__pypy__/interp_dict.py
--- a/pypy/module/__pypy__/interp_dict.py
+++ b/pypy/module/__pypy__/interp_dict.py
@@ -44,3 +44,18 @@
 if not isinstance(w_obj, W_DictMultiObject):
 raise OperationError(space.w_TypeError, space.w_None)
 return w_obj.nondescr_reversed_dict(space)
+
+@unwrap_spec(last=bool)
+def move_to_end(space, w_obj, w_key, last=True):
+"""Move the key in a dictionary object into the first or last position.
+
+This is a __pypy__ function instead of being simply done by calling
+dict.move_to_end(), for CPython compatibility: dictionaries are only
+ordered on PyPy.  You should use the collections.OrderedDict class for
+cases where ordering is important.  That class implements the
+move_to_end() method by calling __pypy__.move_to_end().
+"""
+from pypy.objspace.std.dictmultiobject import W_DictMultiObject
+if not isinstance(w_obj, W_DictMultiObject):
+raise OperationError(space.w_TypeError, space.w_None)
+return w_obj.nondescr_move_to_end(space, w_key, last)
diff --git a/pypy/objspace/std/dictmultiobject.py 
b/pypy/objspace/std/dictmultiobject.py
--- a/pypy/objspace/std/dictmultiobject.py
+++ b/pypy/objspace/std/dictmultiobject.py
@@ -232,6 +232,37 @@
 w_keys = self.w_keys()
 return space.call_method(w_keys, '__reversed__')
 
+def nondescr_move_to_end(self, space, w_key, last_flag):
+"""Not exposed directly to app-level, but via __pypy__.move_to_end().
+"""
+strategy = self.get_strategy()
+if strategy.has_move_to_end:
+strategy.move_to_end(self, w_key, last_flag)
+else:
+# fall-back
+w_value = self.getitem(w_key)
+if w_value is None:
+space.raise_key_error(w_key)
+else:
+self.delitem(w_key)
+if last_flag:
+self.setitem(w_key, w_value)
+else:
+# *very slow* fall-back
+keys_w = []
+values_w = []
+iteratorimplementation = self.iteritems()
+while True:
+w_k, w_v = iteratorimplementation.next_item()
+if w_k is None:
+break
+keys_w.append(w_k)
+values_w.append(w_v)
+self.clear()
+self.setitem(w_key, w_value)
+for i in range(len(keys_w)):
+self.setitem(keys_w[i], values_w[i])
+
 def descr_clear(self, space):
 """D.clear() -> None.  Remove all items from D."""
 self.clear()
@@ -499,7 +530,9 @@
 raise NotImplementedError
 
 has_iterreversed = False
-# no 'getiterreversed': no default implementation available
+has_move_to_end = False
+# no 'getiterreversed' and no 'move_to_end': no default
+# implementation available
 
 def rev_update1_dict_dict(self, w_dict, w_updatedict):
 iteritems = self.iteritems(w_dict)
@@ -783,6 +816,9 @@
 dictimpl.iterreversed = iterreversed
 dictimpl.has_iterreversed = True
 
+if hasattr(dictimpl, 'move_to_end'):
+dictimpl.has_move_to_end = True
+
 @jit.look_inside_iff(lambda self, w_dict, w_updatedict:
  w_dict_unrolling_heuristic(w_dict))
 def rev_update1_dict_dict(self, w_dict, w_updatedict):
@@ -962,6 +998,15 @@
 def getiterreversed(self, w_dict):
 return objectmodel.reversed_dict(self.unerase(w_dict.dstorage))
 
+def move_to_end(self, w_dict, w_key, last_flag):
+if self.is_correct_type(w_key):
+d = self.unerase(w_dict.dstorage)
+key = self.unwrap(w_key)
+objectmodel.move_to_end(d, key, last_flag)
+else:
+self.switch_to_object_strategy(w_dict)
+w_dict.nondescr_move_to_end(w_dict.space, w_key, last_flag)
+
 def prepare_update(self, w_dict,