[pypy-commit] pypy py3k: hg merge default (+ fixes)
mjacob
pypy.commits at gmail.com
Fri May 20 12:57:18 EDT 2016
Author: Manuel Jacob <me at manueljacob.de>
Branch: py3k
Changeset: r84538:df5facd61ba8
Date: 2016-05-20 18:54 +0200
http://bitbucket.org/pypy/pypy/changeset/df5facd61ba8/
Log: hg merge default (+ fixes)
Some tests still fail. E.g. test_verbose_flag_* in
pypy/module/imp/test/test_import.py and test_sre in
pypy/module/cpyext/test/test_typeobject.py.
diff --git a/.hgtags b/.hgtags
--- a/.hgtags
+++ b/.hgtags
@@ -22,3 +22,4 @@
bbd45126bc691f669c4ebdfbd74456cd274c6b92 release-5.0.1
3260adbeba4a8b6659d1cc0d0b41f266769b74da release-5.1
b0a649e90b6642251fb4a765fe5b27a97b1319a9 release-5.1.1
+80ef432a32d9baa4b3c5a54c215e8ebe499f6374 release-5.1.2
diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -93,3 +93,15 @@
.. branch: ufunc-outer
Implement ufunc.outer on numpypy
+
+.. branch: verbose-imports
+
+Support ``pypy -v``: verbose imports. It does not log as much as
+cpython, but it should be enough to help when debugging package layout
+problems.
+
+.. branch: cpyext-macros-cast
+
+Fix some warnings when compiling CPython C extension modules
+
+.. branch: syntax_fix
diff --git a/pypy/interpreter/app_main.py b/pypy/interpreter/app_main.py
--- a/pypy/interpreter/app_main.py
+++ b/pypy/interpreter/app_main.py
@@ -526,6 +526,7 @@
unbuffered,
ignore_environment,
quiet,
+ verbose,
**ignored):
# with PyPy in top of CPython we can only have around 100
# but we need more in the translated PyPy for the compiler package
@@ -658,6 +659,8 @@
inspect = True
else:
# If not interactive, just read and execute stdin normally.
+ if verbose:
+ print_banner(not no_site)
@hidden_applevel
def run_it():
co_stdin = compile(sys.stdin.read(), '<stdin>', 'exec',
@@ -741,10 +744,10 @@
return status
def print_banner(copyright):
- print('Python %s on %s' % (sys.version, sys.platform))
+ print('Python %s on %s' % (sys.version, sys.platform), file=sys.stderr)
if copyright:
print('Type "help", "copyright", "credits" or '
- '"license" for more information.')
+ '"license" for more information.', file=sys.stderr)
STDLIB_WARNING = """\
debug: WARNING: Library path not found, using compiled-in sys.path.
diff --git a/pypy/module/__pypy__/interp_magic.py b/pypy/module/__pypy__/interp_magic.py
--- a/pypy/module/__pypy__/interp_magic.py
+++ b/pypy/module/__pypy__/interp_magic.py
@@ -51,6 +51,11 @@
space.newint(cache.misses.get(name, 0))])
def builtinify(space, w_func):
+ """To implement at app-level modules that are, in CPython,
+ implemented in C: this decorator protects a function from being ever
+ bound like a method. Useful because some tests do things like put
+ a "built-in" function on a class and access it via the instance.
+ """
from pypy.interpreter.function import Function, BuiltinFunction
func = space.interp_w(Function, w_func)
bltn = BuiltinFunction(func)
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
@@ -413,7 +413,16 @@
arg = rffi.cast(ARG, as_pyobj(space, input_arg))
else:
arg = rffi.cast(ARG, input_arg)
- elif is_PyObject(ARG) and is_wrapped:
+ elif ARG == rffi.VOIDP and not is_wrapped:
+ # unlike is_PyObject case above, we allow any kind of
+ # argument -- just, if it's an object, we assume the
+ # caller meant for it to become a PyObject*.
+ if input_arg is None or isinstance(input_arg, W_Root):
+ keepalives += (input_arg,)
+ arg = rffi.cast(ARG, as_pyobj(space, input_arg))
+ else:
+ arg = rffi.cast(ARG, input_arg)
+ elif (is_PyObject(ARG) or ARG == rffi.VOIDP) and is_wrapped:
# build a W_Root, possibly from a 'PyObject *'
if is_pyobj(input_arg):
arg = from_ref(space, input_arg)
@@ -725,6 +734,7 @@
class WrapperGen(object):
wrapper_second_level = None
+ A = lltype.Array(lltype.Char)
def __init__(self, space, signature):
self.space = space
@@ -737,9 +747,13 @@
wrapper_second_level = self.wrapper_second_level
name = callable.__name__
+ pname = lltype.malloc(self.A, len(name), flavor='raw', immortal=True)
+ for i in range(len(name)):
+ pname[i] = name[i]
+
def wrapper(*args):
# no GC here, not even any GC object
- return wrapper_second_level(callable, name, *args)
+ return wrapper_second_level(callable, pname, *args)
wrapper.__name__ = "wrapper for %r" % (callable, )
return wrapper
@@ -747,22 +761,31 @@
@dont_inline
+def _unpack_name(pname):
+ return ''.join([pname[i] for i in range(len(pname))])
+
+ at dont_inline
def deadlock_error(funcname):
+ funcname = _unpack_name(funcname)
fatalerror_notb("GIL deadlock detected when a CPython C extension "
"module calls '%s'" % (funcname,))
@dont_inline
def no_gil_error(funcname):
+ funcname = _unpack_name(funcname)
fatalerror_notb("GIL not held when a CPython C extension "
"module calls '%s'" % (funcname,))
@dont_inline
def not_supposed_to_fail(funcname):
- raise SystemError("The function '%s' was not supposed to fail"
- % (funcname,))
+ funcname = _unpack_name(funcname)
+ print "Error in cpyext, CPython compatibility layer:"
+ print "The function", funcname, "was not supposed to fail"
+ raise SystemError
@dont_inline
def unexpected_exception(funcname, e, tb):
+ funcname = _unpack_name(funcname)
print 'Fatal error in cpyext, CPython compatibility layer, calling',funcname
print 'Either report a bug or consider not using this particular extension'
if not we_are_translated():
@@ -801,9 +824,8 @@
def invalid(err):
"NOT_RPYTHON: translation-time crash if this ends up being called"
raise ValueError(err)
- invalid.__name__ = 'invalid_%s' % name
- def wrapper_second_level(callable, name, *args):
+ def wrapper_second_level(callable, pname, *args):
from pypy.module.cpyext.pyobject import make_ref, from_ref, is_pyobj
from pypy.module.cpyext.pyobject import as_pyobj
# we hope that malloc removal removes the newtuple() that is
@@ -814,7 +836,7 @@
_gil_auto = (gil_auto_workaround and cpyext_glob_tid_ptr[0] != tid)
if gil_acquire or _gil_auto:
if cpyext_glob_tid_ptr[0] == tid:
- deadlock_error(name)
+ deadlock_error(pname)
rgil.acquire()
assert cpyext_glob_tid_ptr[0] == 0
elif pygilstate_ensure:
@@ -827,7 +849,7 @@
args += (pystate.PyGILState_UNLOCKED,)
else:
if cpyext_glob_tid_ptr[0] != tid:
- no_gil_error(name)
+ no_gil_error(pname)
cpyext_glob_tid_ptr[0] = 0
rffi.stackcounter.stacks_counter += 1
@@ -844,6 +866,10 @@
if is_PyObject(typ) and is_wrapped:
assert is_pyobj(arg)
arg_conv = from_ref(space, rffi.cast(PyObject, arg))
+ elif typ == rffi.VOIDP and is_wrapped:
+ # Many macros accept a void* so that one can pass a
+ # PyObject* or a PySomeSubtype*.
+ arg_conv = from_ref(space, rffi.cast(PyObject, arg))
else:
arg_conv = arg
boxed_args += (arg_conv, )
@@ -873,7 +899,7 @@
if failed:
if error_value is CANNOT_FAIL:
- raise not_supposed_to_fail(name)
+ raise not_supposed_to_fail(pname)
retval = error_value
elif is_PyObject(restype):
@@ -893,7 +919,7 @@
retval = rffi.cast(restype, result)
except Exception as e:
- unexpected_exception(name, e, tb)
+ unexpected_exception(pname, e, tb)
return fatal_value
assert lltype.typeOf(retval) == restype
diff --git a/pypy/module/cpyext/cdatetime.py b/pypy/module/cpyext/cdatetime.py
--- a/pypy/module/cpyext/cdatetime.py
+++ b/pypy/module/cpyext/cdatetime.py
@@ -178,67 +178,67 @@
# Accessors
- at cpython_api([PyDateTime_Date], rffi.INT_real, error=CANNOT_FAIL)
+ at cpython_api([rffi.VOIDP], rffi.INT_real, error=CANNOT_FAIL)
def PyDateTime_GET_YEAR(space, w_obj):
"""Return the year, as a positive int.
"""
return space.int_w(space.getattr(w_obj, space.wrap("year")))
- at cpython_api([PyDateTime_Date], rffi.INT_real, error=CANNOT_FAIL)
+ at cpython_api([rffi.VOIDP], rffi.INT_real, error=CANNOT_FAIL)
def PyDateTime_GET_MONTH(space, w_obj):
"""Return the month, as an int from 1 through 12.
"""
return space.int_w(space.getattr(w_obj, space.wrap("month")))
- at cpython_api([PyDateTime_Date], rffi.INT_real, error=CANNOT_FAIL)
+ at cpython_api([rffi.VOIDP], rffi.INT_real, error=CANNOT_FAIL)
def PyDateTime_GET_DAY(space, w_obj):
"""Return the day, as an int from 1 through 31.
"""
return space.int_w(space.getattr(w_obj, space.wrap("day")))
- at cpython_api([PyDateTime_DateTime], rffi.INT_real, error=CANNOT_FAIL)
+ at cpython_api([rffi.VOIDP], rffi.INT_real, error=CANNOT_FAIL)
def PyDateTime_DATE_GET_HOUR(space, w_obj):
"""Return the hour, as an int from 0 through 23.
"""
return space.int_w(space.getattr(w_obj, space.wrap("hour")))
- at cpython_api([PyDateTime_DateTime], rffi.INT_real, error=CANNOT_FAIL)
+ at cpython_api([rffi.VOIDP], rffi.INT_real, error=CANNOT_FAIL)
def PyDateTime_DATE_GET_MINUTE(space, w_obj):
"""Return the minute, as an int from 0 through 59.
"""
return space.int_w(space.getattr(w_obj, space.wrap("minute")))
- at cpython_api([PyDateTime_DateTime], rffi.INT_real, error=CANNOT_FAIL)
+ at cpython_api([rffi.VOIDP], rffi.INT_real, error=CANNOT_FAIL)
def PyDateTime_DATE_GET_SECOND(space, w_obj):
"""Return the second, as an int from 0 through 59.
"""
return space.int_w(space.getattr(w_obj, space.wrap("second")))
- at cpython_api([PyDateTime_DateTime], rffi.INT_real, error=CANNOT_FAIL)
+ at cpython_api([rffi.VOIDP], rffi.INT_real, error=CANNOT_FAIL)
def PyDateTime_DATE_GET_MICROSECOND(space, w_obj):
"""Return the microsecond, as an int from 0 through 999999.
"""
return space.int_w(space.getattr(w_obj, space.wrap("microsecond")))
- at cpython_api([PyDateTime_Time], rffi.INT_real, error=CANNOT_FAIL)
+ at cpython_api([rffi.VOIDP], rffi.INT_real, error=CANNOT_FAIL)
def PyDateTime_TIME_GET_HOUR(space, w_obj):
"""Return the hour, as an int from 0 through 23.
"""
return space.int_w(space.getattr(w_obj, space.wrap("hour")))
- at cpython_api([PyDateTime_Time], rffi.INT_real, error=CANNOT_FAIL)
+ at cpython_api([rffi.VOIDP], rffi.INT_real, error=CANNOT_FAIL)
def PyDateTime_TIME_GET_MINUTE(space, w_obj):
"""Return the minute, as an int from 0 through 59.
"""
return space.int_w(space.getattr(w_obj, space.wrap("minute")))
- at cpython_api([PyDateTime_Time], rffi.INT_real, error=CANNOT_FAIL)
+ at cpython_api([rffi.VOIDP], rffi.INT_real, error=CANNOT_FAIL)
def PyDateTime_TIME_GET_SECOND(space, w_obj):
"""Return the second, as an int from 0 through 59.
"""
return space.int_w(space.getattr(w_obj, space.wrap("second")))
- at cpython_api([PyDateTime_Time], rffi.INT_real, error=CANNOT_FAIL)
+ at cpython_api([rffi.VOIDP], rffi.INT_real, error=CANNOT_FAIL)
def PyDateTime_TIME_GET_MICROSECOND(space, w_obj):
"""Return the microsecond, as an int from 0 through 999999.
"""
@@ -248,14 +248,14 @@
# But it does not seem possible to expose a different structure
# for types defined in a python module like lib/datetime.py.
- at cpython_api([PyDateTime_Delta], rffi.INT_real, error=CANNOT_FAIL)
+ at cpython_api([rffi.VOIDP], rffi.INT_real, error=CANNOT_FAIL)
def PyDateTime_DELTA_GET_DAYS(space, w_obj):
return space.int_w(space.getattr(w_obj, space.wrap("days")))
- at cpython_api([PyDateTime_Delta], rffi.INT_real, error=CANNOT_FAIL)
+ at cpython_api([rffi.VOIDP], rffi.INT_real, error=CANNOT_FAIL)
def PyDateTime_DELTA_GET_SECONDS(space, w_obj):
return space.int_w(space.getattr(w_obj, space.wrap("seconds")))
- at cpython_api([PyDateTime_Delta], rffi.INT_real, error=CANNOT_FAIL)
+ at cpython_api([rffi.VOIDP], rffi.INT_real, error=CANNOT_FAIL)
def PyDateTime_DELTA_GET_MICROSECONDS(space, w_obj):
return space.int_w(space.getattr(w_obj, space.wrap("microseconds")))
diff --git a/pypy/module/cpyext/floatobject.py b/pypy/module/cpyext/floatobject.py
--- a/pypy/module/cpyext/floatobject.py
+++ b/pypy/module/cpyext/floatobject.py
@@ -48,7 +48,7 @@
def PyFloat_AsDouble(space, w_obj):
return space.float_w(space.float(w_obj))
- at cpython_api([PyObject], lltype.Float, error=CANNOT_FAIL)
+ at cpython_api([rffi.VOIDP], lltype.Float, error=CANNOT_FAIL)
def PyFloat_AS_DOUBLE(space, w_float):
"""Return a C double representation of the contents of w_float, but
without error checking."""
diff --git a/pypy/module/cpyext/include/listobject.h b/pypy/module/cpyext/include/listobject.h
--- a/pypy/module/cpyext/include/listobject.h
+++ b/pypy/module/cpyext/include/listobject.h
@@ -1,1 +1,1 @@
-#define PyList_GET_ITEM PyList_GetItem
+#define PyList_GET_ITEM(o, i) PyList_GetItem((PyObject*)(o), (i))
diff --git a/pypy/module/cpyext/listobject.py b/pypy/module/cpyext/listobject.py
--- a/pypy/module/cpyext/listobject.py
+++ b/pypy/module/cpyext/listobject.py
@@ -21,7 +21,7 @@
"""
return space.newlist([None] * len)
- at cpython_api([PyObject, Py_ssize_t, PyObject], PyObject, error=CANNOT_FAIL,
+ at cpython_api([rffi.VOIDP, Py_ssize_t, PyObject], PyObject, error=CANNOT_FAIL,
result_borrowed=True)
def PyList_SET_ITEM(space, w_list, index, w_item):
"""Macro form of PyList_SetItem() without error checking. This is normally
@@ -87,7 +87,7 @@
space.call_method(space.w_list, "insert", w_list, space.wrap(index), w_item)
return 0
- at cpython_api([PyObject], Py_ssize_t, error=CANNOT_FAIL)
+ at cpython_api([rffi.VOIDP], Py_ssize_t, error=CANNOT_FAIL)
def PyList_GET_SIZE(space, w_list):
"""Macro form of PyList_Size() without error checking.
"""
diff --git a/pypy/module/cpyext/sequence.py b/pypy/module/cpyext/sequence.py
--- a/pypy/module/cpyext/sequence.py
+++ b/pypy/module/cpyext/sequence.py
@@ -54,7 +54,7 @@
except OperationError:
raise OperationError(space.w_TypeError, space.wrap(rffi.charp2str(m)))
- at cpython_api([PyObject, Py_ssize_t], PyObject, result_borrowed=True)
+ at cpython_api([rffi.VOIDP, Py_ssize_t], PyObject, result_borrowed=True)
def PySequence_Fast_GET_ITEM(space, w_obj, index):
"""Return the ith element of o, assuming that o was returned by
PySequence_Fast(), o is not NULL, and that i is within bounds.
@@ -67,7 +67,7 @@
"PySequence_Fast_GET_ITEM called but object is not a list or "
"sequence")
- at cpython_api([PyObject], Py_ssize_t, error=CANNOT_FAIL)
+ at cpython_api([rffi.VOIDP], Py_ssize_t, error=CANNOT_FAIL)
def PySequence_Fast_GET_SIZE(space, w_obj):
"""Returns the length of o, assuming that o was returned by
PySequence_Fast() and that o is not NULL. The size can also be
@@ -82,7 +82,7 @@
"PySequence_Fast_GET_SIZE called but object is not a list or "
"sequence")
- at cpython_api([PyObject], PyObjectP)
+ at cpython_api([rffi.VOIDP], PyObjectP)
def PySequence_Fast_ITEMS(space, w_obj):
"""Return the underlying array of PyObject pointers. Assumes that o was returned
by PySequence_Fast() and o is not NULL.
@@ -119,7 +119,7 @@
space.delslice(w_obj, space.wrap(start), space.wrap(end))
return 0
- at cpython_api([PyObject, Py_ssize_t], PyObject)
+ at cpython_api([rffi.VOIDP, Py_ssize_t], PyObject)
def PySequence_ITEM(space, w_obj, i):
"""Return the ith element of o or NULL on failure. Macro form of
PySequence_GetItem() but without checking that
diff --git a/pypy/module/cpyext/setobject.py b/pypy/module/cpyext/setobject.py
--- a/pypy/module/cpyext/setobject.py
+++ b/pypy/module/cpyext/setobject.py
@@ -74,7 +74,7 @@
space.call_method(space.w_set, 'clear', w_set)
return 0
- at cpython_api([PyObject], Py_ssize_t, error=CANNOT_FAIL)
+ at cpython_api([rffi.VOIDP], Py_ssize_t, error=CANNOT_FAIL)
def PySet_GET_SIZE(space, w_s):
"""Macro form of PySet_Size() without error checking."""
return space.int_w(space.len(w_s))
diff --git a/pypy/module/cpyext/test/test_datetime.py b/pypy/module/cpyext/test/test_datetime.py
--- a/pypy/module/cpyext/test/test_datetime.py
+++ b/pypy/module/cpyext/test/test_datetime.py
@@ -117,3 +117,108 @@
datetime.timedelta,
datetime.tzinfo)
module.clear_types()
+
+ def test_macros(self):
+ module = self.import_extension('foo', [
+ ("test_date_macros", "METH_NOARGS",
+ """
+ PyObject* obj;
+ PyDateTime_Date* d;
+ PyDateTime_IMPORT;
+ if (!PyDateTimeAPI) {
+ PyErr_SetString(PyExc_RuntimeError, "No PyDateTimeAPI");
+ return NULL;
+ }
+ obj = PyDate_FromDate(2000, 6, 6);
+ d = (PyDateTime_Date*)obj;
+
+ PyDateTime_GET_YEAR(obj);
+ PyDateTime_GET_YEAR(d);
+
+ PyDateTime_GET_MONTH(obj);
+ PyDateTime_GET_MONTH(d);
+
+ PyDateTime_GET_DAY(obj);
+ PyDateTime_GET_DAY(d);
+
+ return obj;
+ """),
+ ("test_datetime_macros", "METH_NOARGS",
+ """
+ PyDateTime_IMPORT;
+ if (!PyDateTimeAPI) {
+ PyErr_SetString(PyExc_RuntimeError, "No PyDateTimeAPI");
+ return NULL;
+ }
+ PyObject* obj = PyDateTime_FromDateAndTime(2000, 6, 6, 6, 6, 6, 6);
+ PyDateTime_DateTime* dt = (PyDateTime_DateTime*)obj;
+
+ PyDateTime_GET_YEAR(obj);
+ PyDateTime_GET_YEAR(dt);
+
+ PyDateTime_GET_MONTH(obj);
+ PyDateTime_GET_MONTH(dt);
+
+ PyDateTime_GET_DAY(obj);
+ PyDateTime_GET_DAY(dt);
+
+ PyDateTime_DATE_GET_HOUR(obj);
+ PyDateTime_DATE_GET_HOUR(dt);
+
+ PyDateTime_DATE_GET_MINUTE(obj);
+ PyDateTime_DATE_GET_MINUTE(dt);
+
+ PyDateTime_DATE_GET_SECOND(obj);
+ PyDateTime_DATE_GET_SECOND(dt);
+
+ PyDateTime_DATE_GET_MICROSECOND(obj);
+ PyDateTime_DATE_GET_MICROSECOND(dt);
+
+ return obj;
+ """),
+ ("test_time_macros", "METH_NOARGS",
+ """
+ PyDateTime_IMPORT;
+ if (!PyDateTimeAPI) {
+ PyErr_SetString(PyExc_RuntimeError, "No PyDateTimeAPI");
+ return NULL;
+ }
+ PyObject* obj = PyTime_FromTime(6, 6, 6, 6);
+ PyDateTime_Time* t = (PyDateTime_Time*)obj;
+
+ PyDateTime_TIME_GET_HOUR(obj);
+ PyDateTime_TIME_GET_HOUR(t);
+
+ PyDateTime_TIME_GET_MINUTE(obj);
+ PyDateTime_TIME_GET_MINUTE(t);
+
+ PyDateTime_TIME_GET_SECOND(obj);
+ PyDateTime_TIME_GET_SECOND(t);
+
+ PyDateTime_TIME_GET_MICROSECOND(obj);
+ PyDateTime_TIME_GET_MICROSECOND(t);
+
+ return obj;
+ """),
+ ("test_delta_macros", "METH_NOARGS",
+ """
+ PyDateTime_IMPORT;
+ if (!PyDateTimeAPI) {
+ PyErr_SetString(PyExc_RuntimeError, "No PyDateTimeAPI");
+ return NULL;
+ }
+ PyObject* obj = PyDelta_FromDSU(6, 6, 6);
+ PyDateTime_Delta* delta = (PyDateTime_Delta*)obj;
+
+ PyDateTime_DELTA_GET_DAYS(obj);
+ PyDateTime_DELTA_GET_DAYS(delta);
+
+ PyDateTime_DELTA_GET_SECONDS(obj);
+ PyDateTime_DELTA_GET_SECONDS(delta);
+
+ PyDateTime_DELTA_GET_MICROSECONDS(obj);
+ PyDateTime_DELTA_GET_MICROSECONDS(delta);
+
+ return obj;
+ """),
+ ])
diff --git a/pypy/module/cpyext/test/test_floatobject.py b/pypy/module/cpyext/test/test_floatobject.py
--- a/pypy/module/cpyext/test/test_floatobject.py
+++ b/pypy/module/cpyext/test/test_floatobject.py
@@ -77,3 +77,19 @@
neginf = module.return_neginf()
assert neginf < 0
assert math.isinf(neginf)
+
+ def test_macro_accepts_wrong_pointer_type(self):
+ import math
+
+ module = self.import_extension('foo', [
+ ("test_macros", "METH_NOARGS",
+ """
+ PyObject* o = PyFloat_FromDouble(1.0);
+ // no PyFloatObject
+ char* dumb_pointer = (char*)o;
+
+ PyFloat_AS_DOUBLE(o);
+ PyFloat_AS_DOUBLE(dumb_pointer);
+
+ Py_RETURN_NONE;"""),
+ ])
diff --git a/pypy/module/cpyext/test/test_listobject.py b/pypy/module/cpyext/test/test_listobject.py
--- a/pypy/module/cpyext/test/test_listobject.py
+++ b/pypy/module/cpyext/test/test_listobject.py
@@ -137,6 +137,33 @@
module.setlistitem(l,0)
assert l == [None, 2, 3]
+ def test_list_macros(self):
+ """The PyList_* macros cast, and calls expecting that build."""
+ module = self.import_extension('foo', [
+ ("test_macro_invocations", "METH_NOARGS",
+ """
+ PyObject* o = PyList_New(2);
+ PyListObject* l = (PyListObject*)o;
+
+
+ Py_INCREF(o);
+ PyList_SET_ITEM(o, 0, o);
+ Py_INCREF(o);
+ PyList_SET_ITEM(l, 1, o);
+
+ PyList_GET_ITEM(o, 0);
+ PyList_GET_ITEM(l, 1);
+
+ PyList_GET_SIZE(o);
+ PyList_GET_SIZE(l);
+
+ return o;
+ """
+ )
+ ])
+ x = module.test_macro_invocations()
+ assert x[0] is x[1] is x
+
def test_get_item_macro(self):
module = self.import_extension('foo', [
("test_get_item", "METH_NOARGS",
diff --git a/pypy/module/cpyext/test/test_sequence.py b/pypy/module/cpyext/test/test_sequence.py
--- a/pypy/module/cpyext/test/test_sequence.py
+++ b/pypy/module/cpyext/test/test_sequence.py
@@ -155,6 +155,29 @@
result = api.PySequence_Index(w_gen, w_tofind)
assert result == 4
+class AppTestSetObject(AppTestCpythonExtensionBase):
+ def test_sequence_macro_cast(self):
+ module = self.import_extension('foo', [
+ ("test_macro_cast", "METH_NOARGS",
+ """
+ PyObject *o = PyList_New(0);
+ PyListObject* l;
+ PyList_Append(o, o);
+ l = (PyListObject*)o;
+
+ PySequence_Fast_GET_ITEM(o, 0);
+ PySequence_Fast_GET_ITEM(l, 0);
+
+ PySequence_Fast_GET_SIZE(o);
+ PySequence_Fast_GET_SIZE(l);
+
+ PySequence_ITEM(o, 0);
+ PySequence_ITEM(l, 0);
+
+ return o;
+ """
+ )
+ ])
class TestCPyListStrategy(BaseApiTest):
def test_getitem_setitem(self, space, api):
w_l = space.wrap([1, 2, 3, 4])
diff --git a/pypy/module/cpyext/test/test_setobject.py b/pypy/module/cpyext/test/test_setobject.py
--- a/pypy/module/cpyext/test/test_setobject.py
+++ b/pypy/module/cpyext/test/test_setobject.py
@@ -2,6 +2,7 @@
from pypy.module.cpyext.pyobject import PyObject, PyObjectP, make_ref, from_ref
from pypy.module.cpyext.test.test_api import BaseApiTest
+from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
from rpython.rtyper.lltypesystem import rffi, lltype
@@ -45,3 +46,20 @@
w_frozenset = space.newfrozenset([space.wrap(i) for i in [1, 2, 3, 4]])
assert api.PyAnySet_CheckExact(w_set)
assert api.PyAnySet_CheckExact(w_frozenset)
+
+class AppTestSetObject(AppTestCpythonExtensionBase):
+ def test_set_macro_cast(self):
+ module = self.import_extension('foo', [
+ ("test_macro_cast", "METH_NOARGS",
+ """
+ PyObject* o = PySet_New(NULL);
+ // no PySetObject
+ char* dumb_pointer = (char*) o;
+
+ PySet_GET_SIZE(o);
+ PySet_GET_SIZE(dumb_pointer);
+
+ return o;
+ """
+ )
+ ])
diff --git a/pypy/module/cpyext/test/test_unicodeobject.py b/pypy/module/cpyext/test/test_unicodeobject.py
--- a/pypy/module/cpyext/test/test_unicodeobject.py
+++ b/pypy/module/cpyext/test/test_unicodeobject.py
@@ -160,6 +160,26 @@
assert module.compare("abc", b"") == 1
+ def test_unicode_macros(self):
+ """The PyUnicode_* macros cast, and calls expecting that build."""
+ module = self.import_extension('foo', [
+ ("test_macro_invocations", "METH_NOARGS",
+ """
+ PyObject* o = PyUnicode_FromString("");
+ PyUnicodeObject* u = (PyUnicodeObject*)o;
+
+ PyUnicode_GET_SIZE(u);
+ PyUnicode_GET_SIZE(o);
+
+ PyUnicode_GET_DATA_SIZE(u);
+ PyUnicode_GET_DATA_SIZE(o);
+
+ PyUnicode_AS_UNICODE(o);
+ PyUnicode_AS_UNICODE(u);
+ return o;
+ """)])
+ assert module.test_macro_invocations() == u''
+
class TestUnicode(BaseApiTest):
def test_unicodeobject(self, space, api):
assert api.PyUnicode_GET_SIZE(space.wrap(u'späm')) == 4
diff --git a/pypy/module/cpyext/test/test_weakref.py b/pypy/module/cpyext/test/test_weakref.py
--- a/pypy/module/cpyext/test/test_weakref.py
+++ b/pypy/module/cpyext/test/test_weakref.py
@@ -7,7 +7,6 @@
w_ref = api.PyWeakref_NewRef(w_obj, space.w_None)
assert w_ref is not None
assert space.is_w(api.PyWeakref_GetObject(w_ref), w_obj)
- assert space.is_w(api.PyWeakref_GET_OBJECT(w_ref), w_obj)
assert space.is_w(api.PyWeakref_LockObject(w_ref), w_obj)
w_obj = space.newtuple([])
@@ -34,3 +33,26 @@
del w_obj
import gc; gc.collect()
assert space.is_w(api.PyWeakref_LockObject(w_ref), space.w_None)
+
+
+class AppTestWeakReference(AppTestCpythonExtensionBase):
+
+ def test_weakref_macro(self):
+ module = self.import_extension('foo', [
+ ("test_macro_cast", "METH_NOARGS",
+ """
+ // PyExc_Warning is some weak-reffable PyObject*.
+ char* dumb_pointer;
+ PyObject* weakref_obj = PyWeakref_NewRef(PyExc_Warning, NULL);
+ if (!weakref_obj) return weakref_obj;
+ // No public PyWeakReference type.
+ dumb_pointer = (char*) weakref_obj;
+
+ PyWeakref_GET_OBJECT(weakref_obj);
+ PyWeakref_GET_OBJECT(dumb_pointer);
+
+ return weakref_obj;
+ """
+ )
+ ])
+ module.test_macro_cast()
diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py
--- a/pypy/module/cpyext/typeobject.py
+++ b/pypy/module/cpyext/typeobject.py
@@ -18,8 +18,9 @@
Py_TPFLAGS_HEAPTYPE, METH_VARARGS, METH_KEYWORDS, CANNOT_FAIL,
Py_TPFLAGS_HAVE_GETCHARBUFFER, build_type_checkers, StaticObjectBuilder,
PyObjectFields, Py_TPFLAGS_BASETYPE, Py_buffer)
-from pypy.module.cpyext.methodobject import (
- PyDescr_NewWrapper, PyCFunction_NewEx, PyCFunction_typedef, PyMethodDef)
+from pypy.module.cpyext.methodobject import (W_PyCClassMethodObject,
+ PyDescr_NewWrapper, PyCFunction_NewEx, PyCFunction_typedef, PyMethodDef,
+ W_PyCMethodObject, W_PyCFunctionObject)
from pypy.module.cpyext.modsupport import convert_method_defs
from pypy.module.cpyext.pyobject import (
PyObject, make_ref, create_ref, from_ref, get_typedescr, make_typedescr,
@@ -125,6 +126,14 @@
cpython_struct("PyGetSetDescrObject", PyGetSetDescrObjectFields,
PyGetSetDescrObjectStruct, level=2)
+PyMethodDescrObjectStruct = lltype.ForwardReference()
+PyMethodDescrObject = lltype.Ptr(PyMethodDescrObjectStruct)
+PyMethodDescrObjectFields = PyDescrObjectFields + (
+ ("d_method", lltype.Ptr(PyMethodDef)),
+ )
+cpython_struct("PyMethodDescrObject", PyMethodDescrObjectFields,
+ PyMethodDescrObjectStruct, level=2)
+
@bootstrap_function
def init_memberdescrobject(space):
make_typedescr(W_MemberDescr.typedef,
@@ -136,6 +145,16 @@
basestruct=PyGetSetDescrObject.TO,
attach=getsetdescr_attach,
)
+ make_typedescr(W_PyCClassMethodObject.typedef,
+ basestruct=PyMethodDescrObject.TO,
+ attach=methoddescr_attach,
+ realize=classmethoddescr_realize,
+ )
+ make_typedescr(W_PyCMethodObject.typedef,
+ basestruct=PyMethodDescrObject.TO,
+ attach=methoddescr_attach,
+ realize=methoddescr_realize,
+ )
def memberdescr_attach(space, py_obj, w_obj):
"""
@@ -166,6 +185,30 @@
assert isinstance(w_obj, W_GetSetPropertyEx)
py_getsetdescr.c_d_getset = w_obj.getset
+def methoddescr_attach(space, py_obj, w_obj):
+ py_methoddescr = rffi.cast(PyMethodDescrObject, py_obj)
+ # XXX assign to d_dname, d_type?
+ assert isinstance(w_obj, W_PyCFunctionObject)
+ py_methoddescr.c_d_method = w_obj.ml
+
+def classmethoddescr_realize(space, obj):
+ # XXX NOT TESTED When is this ever called?
+ method = rffi.cast(lltype.Ptr(PyMethodDef), obj)
+ w_type = from_ref(space, rffi.cast(PyObject, obj.c_ob_type))
+ w_obj = space.allocate_instance(W_PyCClassMethodObject, w_type)
+ w_obj.__init__(space, method, w_type)
+ track_reference(space, obj, w_obj)
+ return w_obj
+
+def methoddescr_realize(space, obj):
+ # XXX NOT TESTED When is this ever called?
+ method = rffi.cast(lltype.Ptr(PyMethodDef), obj)
+ w_type = from_ref(space, rffi.cast(PyObject, obj.c_ob_type))
+ w_obj = space.allocate_instance(W_PyCMethodObject, w_type)
+ w_obj.__init__(space, method, w_type)
+ track_reference(space, obj, w_obj)
+ return w_obj
+
def convert_getset_defs(space, dict_w, getsets, w_type):
getsets = rffi.cast(rffi.CArrayPtr(PyGetSetDef), getsets)
if getsets:
diff --git a/pypy/module/cpyext/unicodeobject.py b/pypy/module/cpyext/unicodeobject.py
--- a/pypy/module/cpyext/unicodeobject.py
+++ b/pypy/module/cpyext/unicodeobject.py
@@ -183,19 +183,19 @@
"""Get the maximum ordinal for a Unicode character."""
return runicode.UNICHR(runicode.MAXUNICODE)
- at cpython_api([PyObject], rffi.CCHARP, error=CANNOT_FAIL)
+ at cpython_api([rffi.VOIDP], rffi.CCHARP, error=CANNOT_FAIL)
def PyUnicode_AS_DATA(space, ref):
"""Return a pointer to the internal buffer of the object. o has to be a
PyUnicodeObject (not checked)."""
return rffi.cast(rffi.CCHARP, PyUnicode_AS_UNICODE(space, ref))
- at cpython_api([PyObject], Py_ssize_t, error=CANNOT_FAIL)
+ at cpython_api([rffi.VOIDP], Py_ssize_t, error=CANNOT_FAIL)
def PyUnicode_GET_DATA_SIZE(space, w_obj):
"""Return the size of the object's internal buffer in bytes. o has to be a
PyUnicodeObject (not checked)."""
return rffi.sizeof(lltype.UniChar) * PyUnicode_GET_SIZE(space, w_obj)
- at cpython_api([PyObject], Py_ssize_t, error=CANNOT_FAIL)
+ at cpython_api([rffi.VOIDP], Py_ssize_t, error=CANNOT_FAIL)
def PyUnicode_GET_SIZE(space, w_obj):
"""Return the size of the object. o has to be a PyUnicodeObject (not
checked)."""
@@ -222,7 +222,7 @@
ref_unicode = rffi.cast(PyUnicodeObject, ref)
if not ref_unicode.c_buffer:
# Copy unicode buffer
- w_unicode = from_ref(space, ref)
+ w_unicode = from_ref(space, rffi.cast(PyObject, ref))
u = space.unicode_w(w_unicode)
ref_unicode.c_buffer = rffi.unicode2wcharp(u)
return ref_unicode.c_buffer
@@ -235,7 +235,7 @@
w_type = from_ref(space, rffi.cast(PyObject, ref.c_ob_type))
if not space.is_true(space.issubtype(w_type, space.w_unicode)):
raise oefmt(space.w_TypeError, "expected unicode object")
- return PyUnicode_AS_UNICODE(space, ref)
+ return PyUnicode_AS_UNICODE(space, rffi.cast(rffi.VOIDP, ref))
@cpython_api([PyObject], rffi.CCHARP)
def _PyUnicode_AsString(space, ref):
@@ -267,8 +267,7 @@
string may or may not be 0-terminated. It is the responsibility of the caller
to make sure that the wchar_t string is 0-terminated in case this is
required by the application."""
- c_buffer = PyUnicode_AS_UNICODE(space, ref)
- ref = rffi.cast(PyUnicodeObject, ref)
+ c_str = PyUnicode_AS_UNICODE(space, rffi.cast(rffi.VOIDP, ref))
c_length = ref.c_length
# If possible, try to copy the 0-termination as well
diff --git a/pypy/module/cpyext/weakrefobject.py b/pypy/module/cpyext/weakrefobject.py
--- a/pypy/module/cpyext/weakrefobject.py
+++ b/pypy/module/cpyext/weakrefobject.py
@@ -1,6 +1,7 @@
from pypy.module.cpyext.api import cpython_api
from pypy.module.cpyext.pyobject import PyObject
from pypy.module._weakref.interp__weakref import W_Weakref, proxy
+from rpython.rtyper.lltypesystem import rffi
@cpython_api([PyObject, PyObject], PyObject)
def PyWeakref_NewRef(space, w_obj, w_callback):
@@ -37,7 +38,7 @@
"""
return space.call_function(w_ref) # borrowed ref
- at cpython_api([PyObject], PyObject, result_borrowed=True)
+ at cpython_api([rffi.VOIDP], PyObject, result_borrowed=True)
def PyWeakref_GET_OBJECT(space, w_ref):
"""Similar to PyWeakref_GetObject(), but implemented as a macro that does no
error checking.
diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py
--- a/pypy/module/imp/importing.py
+++ b/pypy/module/imp/importing.py
@@ -41,6 +41,14 @@
return '.' + soabi + SO
+def log_pyverbose(space, level, message):
+ if space.sys.w_initialdict is None:
+ return # sys module not initialised, avoid recursion
+ verbose = space.sys.get_flag('verbose')
+ if verbose >= level:
+ w_stderr = space.sys.get('stderr')
+ space.call_method(w_stderr, "write", space.wrap(message))
+
def has_so_extension(space):
return (space.config.objspace.usemodules.cpyext or
space.config.objspace.usemodules._cffi_backend)
@@ -354,6 +362,9 @@
Load a module from a compiled file, execute it, and return its
module object.
"""
+ log_pyverbose(space, 1, "import %s # compiled from %s\n" %
+ (space.str_w(w_modulename), cpathname))
+
if magic != get_pyc_magic(space):
raise oefmt(space.w_ImportError, "Bad magic number in %s", cpathname)
#print "loading pyc file:", cpathname
diff --git a/pypy/module/imp/test/test_import.py b/pypy/module/imp/test/test_import.py
--- a/pypy/module/imp/test/test_import.py
+++ b/pypy/module/imp/test/test_import.py
@@ -46,15 +46,13 @@
if pkgname:
p = p.join(*pkgname.split('.'))
p.ensure(dir=1)
- f = p.join("__init__.py").open('w')
- print >> f, "# package"
- f.close()
+ with p.join("__init__.py").open('w') as f:
+ print >> f, "# package"
for filename, content in entries.items():
filename += '.py'
- f = p.join(filename).open('w')
- print >> f, '#', filename
- print >> f, content
- f.close()
+ with p.join(filename).open('w') as f:
+ print >> f, '#', filename
+ print >> f, content
return p
def setup_directory_structure(cls):
@@ -123,6 +121,9 @@
'a=5\nb=6\rc="""hello\r\nworld"""\r', mode='wb')
p.join('mod.py').write(
'a=15\nb=16\rc="""foo\r\nbar"""\r', mode='wb')
+ setuppkg("verbose1pkg", verbosemod='a = 1729')
+ setuppkg("verbose2pkg", verbosemod='a = 1729')
+ setuppkg("verbose0pkg", verbosemod='a = 1729')
setuppkg("test_bytecode",
a = '',
b = '',
@@ -565,9 +566,8 @@
import test_reload
import time, imp
time.sleep(1)
- f = open(test_reload.__file__, "w")
- f.write("a = 10 // 0\n")
- f.close()
+ with open(test_reload.__file__, "w") as f:
+ f.write("a = 10 // 0\n")
# A failing reload should leave the previous module in sys.modules
raises(ZeroDivisionError, imp.reload, test_reload)
@@ -710,7 +710,8 @@
import pkg
import os
pathname = os.path.join(os.path.dirname(pkg.__file__), 'a.py')
- module = imp.load_module('a', open(pathname),
+ with open(pathname) as fid:
+ module = imp.load_module('a', fid,
'invalid_path_name', ('.py', 'r', imp.PY_SOURCE))
assert module.__name__ == 'a'
assert module.__file__ == 'invalid_path_name'
@@ -745,6 +746,68 @@
else:
raise AssertionError("should have failed")
+ def test_verbose_flag_1(self):
+ output = []
+ class StdErr(object):
+ def write(self, line):
+ output.append(line)
+
+ import sys, imp
+ old_flags = sys.flags
+
+ class Flags(object):
+ verbose = 1
+ def __getattr__(self, name):
+ return getattr(old_flags, name)
+
+ sys.flags = Flags()
+ sys.stderr = StdErr()
+ try:
+ import verbose1pkg.verbosemod
+ finally:
+ imp.reload(sys)
+ assert 'import verbose1pkg # ' in output[-2]
+ assert 'import verbose1pkg.verbosemod # ' in output[-1]
+
+ def test_verbose_flag_2(self):
+ output = []
+ class StdErr(object):
+ def write(self, line):
+ output.append(line)
+
+ import sys, imp
+ old_flags = sys.flags
+
+ class Flags(object):
+ verbose = 2
+ def __getattr__(self, name):
+ return getattr(old_flags, name)
+
+ sys.flags = Flags()
+ sys.stderr = StdErr()
+ try:
+ import verbose2pkg.verbosemod
+ finally:
+ imp.reload(sys)
+ assert any('import verbose2pkg # ' in line
+ for line in output[:-2])
+ assert output[-2].startswith('# trying')
+ assert 'import verbose2pkg.verbosemod # ' in output[-1]
+
+ def test_verbose_flag_0(self):
+ output = []
+ class StdErr(object):
+ def write(self, line):
+ output.append(line)
+
+ import sys, imp
+ sys.stderr = StdErr()
+ try:
+ import verbose0pkg.verbosemod
+ finally:
+ imp.reload(sys)
+ assert not output
+
def test_source_encoding(self):
import imp
import encoded
diff --git a/pypy/tool/release/repackage.sh b/pypy/tool/release/repackage.sh
--- a/pypy/tool/release/repackage.sh
+++ b/pypy/tool/release/repackage.sh
@@ -1,26 +1,33 @@
# Edit these appropriately before running this script
maj=5
min=1
-rev=1
+rev=2
branchname=release-$maj.x # ==OR== release-$maj.$min.x
tagname=release-$maj.$min.$rev # ==OR== release-$maj.$min
+echo checking hg log -r $branchname
hg log -r $branchname || exit 1
+echo checking hg log -r $tagname
hg log -r $tagname || exit 1
# This script will download latest builds from the buildmaster, rename the top
# level directory, and repackage ready to be uploaded to bitbucket. It will also
# download source, assuming a tag for the release already exists, and repackage them.
# The script should be run in an empty directory, i.e. /tmp/release_xxx
-
for plat in linux linux64 linux-armhf-raspbian linux-armhf-raring linux-armel osx64 s390x
do
+ echo downloading package for $plat
wget http://buildbot.pypy.org/nightly/$branchname/pypy-c-jit-latest-$plat.tar.bz2
tar -xf pypy-c-jit-latest-$plat.tar.bz2
rm pypy-c-jit-latest-$plat.tar.bz2
- mv pypy-c-jit-*-$plat pypy-$maj.$min.$rev-$plat
- tar --owner=root --group=root --numeric-owner -cvjf pypy-$maj.$min.$rev-$plat.tar.bz2 pypy-$maj.$min.$rev-$plat
- rm -rf pypy-$maj.$min.$rev-$plat
+ plat_final=$plat
+ if [ $plat = linux ]; then
+ plat_final=linux32
+ fi
+ mv pypy-c-jit-*-$plat pypy-$maj.$min.$rev-$plat_final
+ echo packaging $plat_final
+ tar --owner=root --group=root --numeric-owner -cvjf pypy-$maj.$min.$rev-$plat_final.tar.bz2 pypy-$maj.$min.$rev-$plat_final
+ rm -rf pypy-$maj.$min.$rev-$plat_final
done
plat=win32
diff --git a/pypy/tool/test/test_tab.py b/pypy/tool/test/test_tab.py
--- a/pypy/tool/test/test_tab.py
+++ b/pypy/tool/test/test_tab.py
@@ -7,7 +7,11 @@
ROOT = os.path.abspath(os.path.join(pypydir, '..'))
RPYTHONDIR = os.path.join(ROOT, "rpython")
-EXCLUDE = {'/virt_test/lib/python2.7/site-packages/setuptools'}
+
+EXCLUDE = {'/virt_test'}
+# ^^^ don't look inside this: it is created by virtualenv on buildslaves.
+# It contains third-party installations that may include tabs in their
+# .py files.
def test_no_tabs():
diff --git a/rpython/rlib/rawrefcount.py b/rpython/rlib/rawrefcount.py
--- a/rpython/rlib/rawrefcount.py
+++ b/rpython/rlib/rawrefcount.py
@@ -27,13 +27,13 @@
"""NOT_RPYTHON: set up rawrefcount with the GC. This is only used
for tests; it should not be called at all during translation.
"""
- global _p_list, _o_list, _adr2pypy, _pypy2ob, _ob_set
+ global _p_list, _o_list, _adr2pypy, _pypy2ob, _pypy2ob_rev
global _d_list, _dealloc_trigger_callback
_p_list = []
_o_list = []
_adr2pypy = [None]
_pypy2ob = {}
- _ob_set = set()
+ _pypy2ob_rev = {}
_d_list = []
_dealloc_trigger_callback = dealloc_trigger_callback
@@ -41,23 +41,22 @@
"NOT_RPYTHON: a link where the PyPy object contains some or all the data"
#print 'create_link_pypy\n\t%s\n\t%s' % (p, ob)
assert p not in _pypy2ob
- assert ob._obj not in _ob_set
+ assert ob._obj not in _pypy2ob_rev
assert not ob.c_ob_pypy_link
ob.c_ob_pypy_link = _build_pypy_link(p)
_pypy2ob[p] = ob
+ _pypy2ob_rev[ob._obj] = p
_p_list.append(ob)
- _ob_set.add(ob._obj)
def create_link_pyobj(p, ob):
"""NOT_RPYTHON: a link where the PyObject contains all the data.
from_obj() will not work on this 'p'."""
#print 'create_link_pyobj\n\t%s\n\t%s' % (p, ob)
assert p not in _pypy2ob
- assert ob._obj not in _ob_set
+ assert ob._obj not in _pypy2ob_rev
assert not ob.c_ob_pypy_link
ob.c_ob_pypy_link = _build_pypy_link(p)
_o_list.append(ob)
- _ob_set.add(ob._obj)
def from_obj(OB_PTR_TYPE, p):
"NOT_RPYTHON"
@@ -65,6 +64,7 @@
if ob is None:
return lltype.nullptr(OB_PTR_TYPE.TO)
assert lltype.typeOf(ob) == OB_PTR_TYPE
+ assert _pypy2ob_rev[ob._obj] is p
return ob
def to_obj(Class, ob):
@@ -111,8 +111,10 @@
new_p_list.append(ob)
else:
p = detach(ob, wr_p_list)
- del _pypy2ob[p]
- del p
+ ob_test = _pypy2ob.pop(p)
+ p_test = _pypy2ob_rev.pop(ob_test._obj)
+ assert p_test is p
+ del p, p_test
ob = None
_p_list = Ellipsis
@@ -156,6 +158,10 @@
p = attach(ob, wr, _p_list)
if p is not None:
_pypy2ob[p] = ob
+ _pypy2ob_rev.clear() # rebuild this dict from scratch
+ for p, ob in _pypy2ob.items():
+ assert ob._obj not in _pypy2ob_rev
+ _pypy2ob_rev[ob._obj] = p
_o_list = []
for ob, wr in wr_o_list:
attach(ob, wr, _o_list)
More information about the pypy-commit
mailing list