From 09a88804f96726dc19c28e11aa3108ac25f1fb77 Mon Sep 17 00:00:00 2001 From: Patience Shyu Date: Fri, 27 Jul 2018 09:47:15 +0200 Subject: [PATCH 1/8] add failing tests for contains/not contains --- tests/structures/test_comparisons.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/structures/test_comparisons.py b/tests/structures/test_comparisons.py index d58e5d081c..fafe368db6 100644 --- a/tests/structures/test_comparisons.py +++ b/tests/structures/test_comparisons.py @@ -583,3 +583,12 @@ def test_multiple_comparisons(self): print(x == (50 + 50) < 2000) print(x == (50 + 50) > 2000) """) + + @expectedFailure + def test_bad_in(self): + self.assertCodeExecution(""" + print('abc' in 'abc') + print(0 in 0) + print(0 not in 0) + print('abc' not in 'abc') + """) From 402c6ec06bf4a7364428742ce00cb334f5a14ad7 Mon Sep 17 00:00:00 2001 From: Patience Shyu Date: Fri, 27 Jul 2018 11:02:14 +0200 Subject: [PATCH 2/8] fix str.__contains__ --- python/common/org/python/types/Str.java | 6 ++++-- tests/datatypes/test_str.py | 8 ++++++++ tests/structures/test_comparisons.py | 1 - 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/python/common/org/python/types/Str.java b/python/common/org/python/types/Str.java index 6b4f30160e..b5f354ed37 100644 --- a/python/common/org/python/types/Str.java +++ b/python/common/org/python/types/Str.java @@ -391,7 +391,7 @@ public org.python.Object __iter__() { __doc__ = "Return key in self.", args = {"item"} ) - public org.python.types.Int __contains__(org.python.Object item) { + public org.python.Object __contains__(org.python.Object item) { if (item instanceof org.python.types.Str) { int substr_exists = 0; @@ -399,6 +399,8 @@ public org.python.types.Int __contains__(org.python.Object item) { if (this.value.length() == 0 && item_str.value.length() == 0) { substr_exists = 1; + } else if (this.value == item_str.value) { + substr_exists = 1; } else { for (int i = 0; i < this.value.length() - item_str.value.length(); i++) { boolean mismatch = false; @@ -413,7 +415,7 @@ public org.python.types.Int __contains__(org.python.Object item) { } } } - return org.python.types.Int.getInt(substr_exists); + return org.python.types.Bool.getBool(substr_exists); } if (org.Python.VERSION < 0x03060000) { throw new org.python.exceptions.TypeError("Can't convert '" + item.typeName() + "' object to str implicitly"); diff --git a/tests/datatypes/test_str.py b/tests/datatypes/test_str.py index 2869e81aaa..90870cd3fd 100644 --- a/tests/datatypes/test_str.py +++ b/tests/datatypes/test_str.py @@ -878,6 +878,14 @@ def test_zfill(self): print(err) """) + def test_contains(self): + self.assertCodeExecution(""" + print('abc' in 'abc') + print('a' in 'abc') + print('a' in '') + print('' in 'a') + """) + class UnaryStrOperationTests(UnaryOperationTestCase, TranspileTestCase): data_type = 'str' diff --git a/tests/structures/test_comparisons.py b/tests/structures/test_comparisons.py index fafe368db6..09b0b08ad0 100644 --- a/tests/structures/test_comparisons.py +++ b/tests/structures/test_comparisons.py @@ -587,7 +587,6 @@ def test_multiple_comparisons(self): @expectedFailure def test_bad_in(self): self.assertCodeExecution(""" - print('abc' in 'abc') print(0 in 0) print(0 not in 0) print('abc' not in 'abc') From a12d7504a651506df44a0defb58ea1c2a1e265a3 Mon Sep 17 00:00:00 2001 From: Patience Shyu Date: Fri, 27 Jul 2018 11:14:19 +0200 Subject: [PATCH 3/8] __not_contains__ checks __contains__ --- python/common/org/python/types/Object.java | 6 +++++- python/common/org/python/types/Str.java | 2 +- tests/datatypes/test_str.py | 5 +++++ tests/structures/test_comparisons.py | 1 - 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/python/common/org/python/types/Object.java b/python/common/org/python/types/Object.java index ff7f82260d..a4e5350cdf 100644 --- a/python/common/org/python/types/Object.java +++ b/python/common/org/python/types/Object.java @@ -557,7 +557,11 @@ public org.python.Object __contains__(org.python.Object item) { args = {"item"} ) public org.python.Object __not_contains__(org.python.Object item) { - throw new org.python.exceptions.AttributeError(this, "__not_contains__"); + try { + return org.python.types.Bool.getBool(!((org.python.types.Bool) this.__contains__(item)).value); + } catch (org.python.exceptions.AttributeError e) { + throw new org.python.exceptions.AttributeError(this, "__not_contains__"); + } } /** diff --git a/python/common/org/python/types/Str.java b/python/common/org/python/types/Str.java index b5f354ed37..1b519416f0 100644 --- a/python/common/org/python/types/Str.java +++ b/python/common/org/python/types/Str.java @@ -400,7 +400,7 @@ public org.python.Object __contains__(org.python.Object item) { if (this.value.length() == 0 && item_str.value.length() == 0) { substr_exists = 1; } else if (this.value == item_str.value) { - substr_exists = 1; + substr_exists = 1; } else { for (int i = 0; i < this.value.length() - item_str.value.length(); i++) { boolean mismatch = false; diff --git a/tests/datatypes/test_str.py b/tests/datatypes/test_str.py index 90870cd3fd..8ea2d9e174 100644 --- a/tests/datatypes/test_str.py +++ b/tests/datatypes/test_str.py @@ -884,6 +884,11 @@ def test_contains(self): print('a' in 'abc') print('a' in '') print('' in 'a') + + print('abc' not in 'abc') + print('a' not in 'abc') + print('a' not in '') + print('' in 'a') """) diff --git a/tests/structures/test_comparisons.py b/tests/structures/test_comparisons.py index 09b0b08ad0..56701b0878 100644 --- a/tests/structures/test_comparisons.py +++ b/tests/structures/test_comparisons.py @@ -589,5 +589,4 @@ def test_bad_in(self): self.assertCodeExecution(""" print(0 in 0) print(0 not in 0) - print('abc' not in 'abc') """) From c3cae6cfeb9411a178dac9781671848ce4959266 Mon Sep 17 00:00:00 2001 From: Patience Shyu Date: Mon, 30 Jul 2018 10:18:37 +0200 Subject: [PATCH 4/8] fix __contains__ on non-iterable types --- python/common/org/python/types/Object.java | 35 +++++++++++++--------- tests/structures/test_comparisons.py | 23 +++++++++++++- 2 files changed, 43 insertions(+), 15 deletions(-) diff --git a/python/common/org/python/types/Object.java b/python/common/org/python/types/Object.java index d4e3434b63..62698f4a5d 100644 --- a/python/common/org/python/types/Object.java +++ b/python/common/org/python/types/Object.java @@ -1368,22 +1368,29 @@ public static org.python.Object __contains__(org.python.Object v, org.python.Obj org.python.Object result = null; if (v_builtin) { - result = v.__contains__(w); - } else { - result = invokeComparison(v, w, "__contains__"); - } - - if (result != org.python.types.NotImplementedType.NOT_IMPLEMENTED) { + try { + result = v.__contains__(w); + } catch (org.python.exceptions.AttributeError e) { + if (org.Python.VERSION < 0x03060000) { + throw new org.python.exceptions.TypeError(String.format( + "unorderable types: %s() %s %s()", v.typeName(), "in", w.typeName())); + } else { + throw new org.python.exceptions.TypeError(String.format("argument of type '%s' is not iterable", v.typeName())); + } + } return result; - } - - // Error case - if (org.Python.VERSION < 0x03060000) { - throw new org.python.exceptions.TypeError(String.format( - "unorderable types: %s() %s %s()", v.typeName(), "in", w.typeName())); } else { - throw new org.python.exceptions.TypeError(String.format( - "'%s' not supported between instances of '%s' and '%s'", "in", v.typeName(), w.typeName())); + try { + result = invokeComparison(v, w, "__contains__"); + } catch (org.python.exceptions.AttributeError e) { + if (org.Python.VERSION < 0x03060000) { + throw new org.python.exceptions.TypeError(String.format( + "unorderable types: %s() %s %s()", v.typeName(), "in", w.typeName())); + } else { + throw new org.python.exceptions.TypeError(String.format("argument of type '%s' is not iterable", v.typeName())); + } + } + return result; } } diff --git a/tests/structures/test_comparisons.py b/tests/structures/test_comparisons.py index 56701b0878..55f2af36c9 100644 --- a/tests/structures/test_comparisons.py +++ b/tests/structures/test_comparisons.py @@ -584,9 +584,30 @@ def test_multiple_comparisons(self): print(x == (50 + 50) > 2000) """) + def test_bad_contains(self): + self.assertCodeExecution(""" + try: + print(0 in 0) + except TypeError as e: + print(e) + + try: + print(0 in True) + except TypeError as e: + print(e) + + class MyClass(): + value = "I am not iterable!" + x = MyClass() + + try: + print(0 in x) + except TypeError as e: + print(e) + """) + @expectedFailure def test_bad_in(self): self.assertCodeExecution(""" - print(0 in 0) print(0 not in 0) """) From 30f66470cc0f925b79720ce74da6f378c0296fc6 Mon Sep 17 00:00:00 2001 From: Patience Shyu Date: Mon, 30 Jul 2018 10:33:22 +0200 Subject: [PATCH 5/8] fix error messages for python 3.4 --- python/common/org/python/types/Object.java | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/python/common/org/python/types/Object.java b/python/common/org/python/types/Object.java index 62698f4a5d..79ac3e405b 100644 --- a/python/common/org/python/types/Object.java +++ b/python/common/org/python/types/Object.java @@ -1371,24 +1371,14 @@ public static org.python.Object __contains__(org.python.Object v, org.python.Obj try { result = v.__contains__(w); } catch (org.python.exceptions.AttributeError e) { - if (org.Python.VERSION < 0x03060000) { - throw new org.python.exceptions.TypeError(String.format( - "unorderable types: %s() %s %s()", v.typeName(), "in", w.typeName())); - } else { - throw new org.python.exceptions.TypeError(String.format("argument of type '%s' is not iterable", v.typeName())); - } + throw new org.python.exceptions.TypeError(String.format("argument of type '%s' is not iterable", v.typeName())); } return result; } else { try { result = invokeComparison(v, w, "__contains__"); } catch (org.python.exceptions.AttributeError e) { - if (org.Python.VERSION < 0x03060000) { - throw new org.python.exceptions.TypeError(String.format( - "unorderable types: %s() %s %s()", v.typeName(), "in", w.typeName())); - } else { - throw new org.python.exceptions.TypeError(String.format("argument of type '%s' is not iterable", v.typeName())); - } + throw new org.python.exceptions.TypeError(String.format("argument of type '%s' is not iterable", v.typeName())); } return result; } From 25901dcc8b75b1f7fa358872e2b89416c0e1f374 Mon Sep 17 00:00:00 2001 From: Patience Shyu Date: Mon, 30 Jul 2018 10:40:54 +0200 Subject: [PATCH 6/8] __not_contains__ inverses the result of __contains__ --- python/common/org/python/types/Object.java | 23 ++-------------------- tests/structures/test_comparisons.py | 22 ++++++++++++++++++--- 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/python/common/org/python/types/Object.java b/python/common/org/python/types/Object.java index 79ac3e405b..9c9d943510 100644 --- a/python/common/org/python/types/Object.java +++ b/python/common/org/python/types/Object.java @@ -1385,27 +1385,8 @@ public static org.python.Object __contains__(org.python.Object v, org.python.Obj } public static org.python.Object __not_contains__(org.python.Object v, org.python.Object w) { - boolean v_builtin = isBuiltin(v); - org.python.Object result = null; - // Normal case - if (v_builtin) { - result = v.__not_contains__(w); - } else { - result = invokeComparison(v, w, "__not_contains__"); - } - - if (result != org.python.types.NotImplementedType.NOT_IMPLEMENTED) { - return result; - } - - // Error case - if (org.Python.VERSION < 0x03060000) { - throw new org.python.exceptions.TypeError(String.format( - "unorderable types: %s() %s %s()", v.typeName(), "not in", w.typeName())); - } else { - throw new org.python.exceptions.TypeError(String.format( - "'%s' not supported between instances of '%s' and '%s'", "not in", v.typeName(), w.typeName())); - } + org.python.Object containsObj = org.python.types.Object.__contains__(v, w); + return org.python.types.Bool.getBool(!((org.python.types.Bool) containsObj).value); } private static org.python.Object invokeComparison(org.python.Object x, org.python.Object y, String methodName) { diff --git a/tests/structures/test_comparisons.py b/tests/structures/test_comparisons.py index 55f2af36c9..eccc5b06e5 100644 --- a/tests/structures/test_comparisons.py +++ b/tests/structures/test_comparisons.py @@ -606,8 +606,24 @@ class MyClass(): print(e) """) - @expectedFailure - def test_bad_in(self): + def test_bad_not_contains(self): self.assertCodeExecution(""" - print(0 not in 0) + try: + print(0 not in 0) + except TypeError as e: + print(e) + + try: + print(0 not in True) + except TypeError as e: + print(e) + + class MyClass(): + value = "I am not iterable!" + x = MyClass() + + try: + print(0 not in x) + except TypeError as e: + print(e) """) From 800412631df0829bbf8e55a2127ece039c0e00f8 Mon Sep 17 00:00:00 2001 From: Patience Shyu Date: Mon, 30 Jul 2018 11:06:29 +0200 Subject: [PATCH 7/8] remove __not_contains__ attribute --- python/common/org/python/Object.java | 1 - python/common/org/python/types/Dict.java | 14 -------------- python/common/org/python/types/DictItems.java | 11 +---------- python/common/org/python/types/DictValues.java | 8 -------- python/common/org/python/types/FrozenSet.java | 8 -------- python/common/org/python/types/Object.java | 12 ------------ python/common/org/python/types/Set.java | 8 -------- python/common/org/python/types/Super.java | 8 -------- 8 files changed, 1 insertion(+), 69 deletions(-) diff --git a/python/common/org/python/Object.java b/python/common/org/python/Object.java index 10a186233c..21ba0c4838 100644 --- a/python/common/org/python/Object.java +++ b/python/common/org/python/Object.java @@ -170,7 +170,6 @@ public interface Object extends Comparable { public org.python.Object __invert__(); public org.python.Object __not__(); - public org.python.Object __not_contains__(org.python.Object item); public org.python.Object __complex__(org.python.Object real, org.python.Object imag); public org.python.Object __int__(); diff --git a/python/common/org/python/types/Dict.java b/python/common/org/python/types/Dict.java index bcce383a9a..520dc92175 100644 --- a/python/common/org/python/types/Dict.java +++ b/python/common/org/python/types/Dict.java @@ -328,20 +328,6 @@ public org.python.Object __contains__(org.python.Object item) { } } - @org.python.Method( - __doc__ = "", - args = {"item"} - ) - public org.python.Object __not_contains__(org.python.Object item) { - // allow unhashable type error to be percolated up. - try { - __getitem__(item); - return org.python.types.Bool.FALSE; - } catch (org.python.exceptions.KeyError e) { - return org.python.types.Bool.TRUE; - } - } - @org.python.Method( __doc__ = "D.clear() -> None. Remove all items from D." ) diff --git a/python/common/org/python/types/DictItems.java b/python/common/org/python/types/DictItems.java index 59f3aa8fc9..2f945af4bf 100644 --- a/python/common/org/python/types/DictItems.java +++ b/python/common/org/python/types/DictItems.java @@ -181,16 +181,7 @@ public org.python.Object __contains__(org.python.Object item) { org.python.types.Set set = new org.python.types.Set(this.toTupleSet()); return set.__contains__(item); } - - @org.python.Method( - __doc__ = "", - args = {"item"} - ) - public org.python.Object __not_contains__(org.python.Object other) { - org.python.types.Set set = new org.python.types.Set(this.toTupleSet()); - return set.__not_contains__(other); - } - + @org.python.Method( __doc__ = "Return self Date: Mon, 30 Jul 2018 11:11:36 +0200 Subject: [PATCH 8/8] fix java checkstyle issues --- python/common/org/python/types/DictItems.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/common/org/python/types/DictItems.java b/python/common/org/python/types/DictItems.java index 2f945af4bf..9b04c41390 100644 --- a/python/common/org/python/types/DictItems.java +++ b/python/common/org/python/types/DictItems.java @@ -181,7 +181,7 @@ public org.python.Object __contains__(org.python.Object item) { org.python.types.Set set = new org.python.types.Set(this.toTupleSet()); return set.__contains__(item); } - + @org.python.Method( __doc__ = "Return self