From: <ped...@us...> - 2009-01-10 12:39:27
|
Revision: 5908 http://jython.svn.sourceforge.net/jython/?rev=5908&view=rev Author: pedronis Date: 2009-01-10 12:39:15 +0000 (Sat, 10 Jan 2009) Log Message: ----------- yet another try at binop rule, with more exhaustive tests (verified against cpython) that now pass see also PyPy issue 412 Modified Paths: -------------- trunk/jython/Lib/test/test_descr_jy.py trunk/jython/src/org/python/core/PyObject.java trunk/jython/src/org/python/core/PyType.java Modified: trunk/jython/Lib/test/test_descr_jy.py =================================================================== --- trunk/jython/Lib/test/test_descr_jy.py 2009-01-10 03:53:36 UTC (rev 5907) +++ trunk/jython/Lib/test/test_descr_jy.py 2009-01-10 12:39:15 UTC (rev 5908) @@ -368,13 +368,148 @@ except AttributeError, e: self.assertEquals("Custom message", str(e)) +# try to test more exhaustively binop overriding combination cases +class Base(object): + def __init__(self, name): + self.name = name + +def lookup_where(obj, name): + mro = type(obj).__mro__ + for t in mro: + if name in t.__dict__: + return t.__dict__[name], t + return None, None + +def refop(x, y, opname, ropname): + # this has been validated by running the tests on top of cpython + # so for the space of possibilities that the tests touch it is known + # to behave like cpython as long as the latter doesn't change its own + # algorithm + t1 = type(x) + t2 = type(y) + op, where1 = lookup_where(x, opname) + rop, where2 = lookup_where(y, ropname) + if op is None and rop is not None: + return rop(y, x) + if rop and where1 is not where2: + if (issubclass(t2, t1) and not issubclass(where1, where2) + and not issubclass(t1, where2) + ): + return rop(y, x) + if op is None: + return "TypeError" + return op(x,y) + +def do_test(X, Y, name, impl): + x = X('x') + y = Y('y') + opname = '__%s__' % name + ropname = '__r%s__' % name + + count = [0] + fail = [] + + def check(z1, z2): + ref = refop(z1, z2, opname, ropname) + try: + v = impl(z1, z2) + except TypeError: + v = "TypeError" + if v != ref: + fail.append(count[0]) + + def override_in_hier(n=6): + if n == 0: + count[0] += 1 + check(x, y) + check(y, x) + return + + f = lambda self, other: (n, self.name, other.name) + if n%2 == 0: + name = opname + else: + name = ropname + + for C in Y.__mro__: + if name in C.__dict__: + continue + if C is not object: + setattr(C, name, f) + override_in_hier(n-1) + if C is not object: + delattr(C, name) + + override_in_hier() + #print count[0] + return fail + +class BinopCombinationsTestCase(unittest.TestCase): + + def test_binop_combinations_mul(self): + class X(Base): + pass + class Y(X): + pass + + fail = do_test(X, Y, 'mul', lambda x,y: x*y) + #print len(fail) + self.assert_(not fail) + + def test_binop_combinations_sub(self): + class X(Base): + pass + class Y(X): + pass + + fail = do_test(X, Y, 'sub', lambda x,y: x-y) + #print len(fail) + self.assert_(not fail) + + def test_binop_combinations_pow(self): + class X(Base): + pass + class Y(X): + pass + + fail = do_test(X, Y, 'pow', lambda x,y: x**y) + #print len(fail) + self.assert_(not fail) + + def test_binop_combinations_more_exhaustive(self): + class X(Base): + pass + + class B1(object): + pass + + class B2(object): + pass + + class X1(B1, X, B2): + pass + + class C1(object): + pass + + class C2(object): + pass + + class Y(C1, X1, C2): + pass + + fail = do_test(X, Y, 'sub', lambda x,y: x-y) + #print len(fail) + self.assert_(not fail) + def test_main(): test_support.run_unittest(TestDescrTestCase, SubclassDescrTestCase, InPlaceTestCase, DescrExceptionsTestCase, - GetAttrTestCase) + GetAttrTestCase, + BinopCombinationsTestCase) if __name__ == '__main__': test_main() Modified: trunk/jython/src/org/python/core/PyObject.java =================================================================== --- trunk/jython/src/org/python/core/PyObject.java 2009-01-10 03:53:36 UTC (rev 5907) +++ trunk/jython/src/org/python/core/PyObject.java 2009-01-10 12:39:15 UTC (rev 5908) @@ -1888,14 +1888,16 @@ * test_descr.subclass_right_op. */ PyObject o1 = this; - int[] where = new int[1]; - int where1, where2; - PyObject impl1 = t1.lookup_where_index(left, where); + PyObject[] where = new PyObject[1]; + PyObject where1 = null, where2 = null; + PyObject impl1 = t1.lookup_where(left, where); where1 = where[0]; - PyObject impl2 = t2.lookup_where_index(right, where); + PyObject impl2 = t2.lookup_where(right, where); where2 = where[0]; - if (impl2 != null && where1 < where2 && (t2.isSubType(t1) || - isStrUnicodeSpecialCase(t1, t2, op))) { + if (impl2 != null && impl1 != null && where1 != where2 && + (t2.isSubType(t1) && !Py.isSubClass(where1, where2) + && !Py.isSubClass(t1, where2) || + isStrUnicodeSpecialCase(t1, t2, op))) { PyObject tmp = o1; o1 = o2; o2 = tmp; Modified: trunk/jython/src/org/python/core/PyType.java =================================================================== --- trunk/jython/src/org/python/core/PyType.java 2009-01-10 03:53:36 UTC (rev 5907) +++ trunk/jython/src/org/python/core/PyType.java 2009-01-10 12:39:15 UTC (rev 5908) @@ -915,34 +915,6 @@ return null; } - /** - * Like lookup but also provides (in where[0]) the index of the type in the reversed - * mro -- that is, how many subtypes away from the base object the type is. - * - * @param name attribute name (must be interned) - * @param where an int[] with a length of at least 1 - * @return found PyObject or null - */ - public PyObject lookup_where_index(String name, int[] where) { - PyObject[] mro = this.mro; - if (mro == null) { - return null; - } - int i = mro.length; - for (PyObject t : mro) { - i--; - PyObject dict = t.fastGetDict(); - if (dict != null) { - PyObject obj = dict.__finditem__(name); - if (obj != null) { - where[0] = i; - return obj; - } - } - } - return null; - } - public PyObject super_lookup(PyType ref, String name) { PyObject[] mro = this.mro; if (mro == null) { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |