From d6192cd927de41bb169fde6e693a3dd9b0ae2216 Mon Sep 17 00:00:00 2001 From: TheAnyKey Date: Thu, 7 May 2020 19:48:23 +0000 Subject: [PATCH 1/4] merged from other brach --- tests/snippets/dict_union.py | 83 ++++++++++++++++++++++++++++++++++++ vm/src/obj/objdict.rs | 43 +++++++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 tests/snippets/dict_union.py diff --git a/tests/snippets/dict_union.py b/tests/snippets/dict_union.py new file mode 100644 index 0000000000..29e0718d45 --- /dev/null +++ b/tests/snippets/dict_union.py @@ -0,0 +1,83 @@ + +import testutils + +def test_dunion_ior0(): + a={1:2,2:3} + b={3:4,5:6} + a|=b + + assert a == {1:2,2:3,3:4,5:6}, f"wrong value assigned {a=}" + assert b == {3:4,5:6}, f"right hand side modified, {b=}" + +def test_dunion_or0(): + a={1:2,2:3} + b={3:4,5:6} + c=a|b + + assert a == {1:2,2:3}, f"left hand side of non-assignment operator modified {a=}" + assert b == {3:4,5:6}, f"right hand side of non-assignment operator modified, {b=}" + assert c == {1:2,2:3, 3:4, 5:6}, f"unexpected result of dict union {c=}" + + +def test_dunion_or1(): + a={1:2,2:3} + b={3:4,5:6} + c=a.__or__(b) + + assert a == {1:2,2:3}, f"left hand side of non-assignment operator modified {a=}" + assert b == {3:4,5:6}, f"right hand side of non-assignment operator modified, {b=}" + assert c == {1:2,2:3, 3:4, 5:6}, f"unexpected result of dict union {c=}" + + +def test_dunion_ror0(): + a={1:2,2:3} + b={3:4,5:6} + c=b.__ror__(a) + + assert a == {1:2,2:3}, f"left hand side of non-assignment operator modified {a=}" + assert b == {3:4,5:6}, f"right hand side of non-assignment operator modified, {b=}" + assert c == {1:2,2:3, 3:4, 5:6}, f"unexpected result of dict union {c=}" + + +def test_dunion_other_types(): + def perf_test_or(other_obj): + d={1:2} + try: + d.__or__(other_obj) + except: + return True + return False + + def perf_test_ior(other_obj): + d={1:2} + try: + d.__ior__(other_obj) + except: + return True + return False + + def perf_test_ror(other_obj): + d={1:2} + try: + d.__ror__(other_obj) + except: + return True + return False + + test_fct={'__or__':perf_test_or, '__ror__':perf_test_ror, '__ior__':perf_test_ior} + others=['FooBar', 42, [36], set([19]), ['aa'], None] + for tfn,tf in test_fct.items(): + for other in others: + assert tf(other), f"Failed: dict {tfn}, accepted {other}" + + + + +testutils.skip_if_unsupported(3,9,test_dunion_ior0) +testutils.skip_if_unsupported(3,9,test_dunion_or0) +testutils.skip_if_unsupported(3,9,test_dunion_or1) +testutils.skip_if_unsupported(3,9,test_dunion_ror0) +testutils.skip_if_unsupported(3,9,test_dunion_other_types) + + + diff --git a/vm/src/obj/objdict.rs b/vm/src/obj/objdict.rs index a5330bdbcf..e2cdb108db 100644 --- a/vm/src/obj/objdict.rs +++ b/vm/src/obj/objdict.rs @@ -104,6 +104,17 @@ impl PyDictRef { Ok(()) } + fn merge_dict( + dict: &DictContentType, + dict_other: PyDictRef, + vm: &VirtualMachine, + ) -> PyResult<()> { + for (key, value) in dict_other { + dict.insert(vm, &key, value)?; + } + Ok(()) + } + #[pyclassmethod] fn fromkeys( class: PyClassRef, @@ -320,6 +331,38 @@ impl PyDictRef { PyDictRef::merge(&self.entries, dict_obj, kwargs, vm) } + #[pymethod(name = "__ior__")] + fn ior(self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { + let dicted: Result = other.clone().downcast(); + if let Ok(other) = dicted { + PyDictRef::merge_dict(&self.entries, other, vm)?; + return Ok(self.into_object()); + } + Err(vm.new_type_error("__ior__ not implemented for non-dict type".to_owned())) + } + + #[pymethod(name = "__ror__")] + fn ror(self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { + let dicted: Result = other.clone().downcast(); + if let Ok(other) = dicted { + let other_cp = other.copy(); + PyDictRef::merge_dict(&other_cp.entries, self, vm)?; + return Ok(other_cp); + } + Err(vm.new_type_error("__ror__ not implemented for non-dict type".to_owned())) + } + + #[pymethod(name = "__or__")] + fn or(self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { + let dicted: Result = other.clone().downcast(); + if let Ok(other) = dicted { + let self_cp = self.copy(); + PyDictRef::merge_dict(&self_cp.entries, other, vm)?; + return Ok(self_cp); + } + Err(vm.new_type_error("__or__ not implemented for non-dict type".to_owned())) + } + #[pymethod] fn pop( self, From a447b886148174abc73a4a8f949b8231cb5932ec Mon Sep 17 00:00:00 2001 From: TheAnyKey Date: Fri, 8 May 2020 08:49:09 +0000 Subject: [PATCH 2/4] merges testutils --- tests/snippets/testutils.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/snippets/testutils.py b/tests/snippets/testutils.py index 8a9fdddb2f..c779d2c898 100644 --- a/tests/snippets/testutils.py +++ b/tests/snippets/testutils.py @@ -1,3 +1,6 @@ +import platform +import sys + def assert_raises(expected, *args, _msg=None, **kw): if args: f, f_args = args[0], args[1:] @@ -67,3 +70,26 @@ def assert_isinstance(obj, klass): def assert_in(a, b): _assert_print(lambda: a in b, [a, 'in', b]) + +def skip_if_unsupported(req_maj_vers, req_min_vers, test_fct): + def exec(): + test_fct() + + if platform.python_implementation() == 'RustPython': + exec() + elif sys.version_info.major>=req_maj_vers and sys.version_info.minor>=req_min_vers: + exec() + else: + print(f'Skipping test as a higher python version is required. Using {platform.python_implementation()} {platform.python_version()}') + +def fail_if_unsupported(req_maj_vers, req_min_vers, test_fct): + def exec(): + test_fct() + + if platform.python_implementation() == 'RustPython': + exec() + elif sys.version_info.major>=req_maj_vers and sys.version_info.minor>=req_min_vers: + exec() + else: + assert False, f'Test cannot performed on this python version. {platform.python_implementation()} {platform.python_version()}' + From 84a6e8e8df72a7ceeb7f45781857b70ed0a7b06e Mon Sep 17 00:00:00 2001 From: TheAnyKey Date: Fri, 8 May 2020 15:28:46 +0000 Subject: [PATCH 3/4] merged from TheAnyKey/p39_string_rem_pre_suffix --- tests/snippets/strings.py | 72 ++++++++++++++++++++++++++++++++++++++- vm/src/obj/objstr.rs | 16 +++++++++ 2 files changed, 87 insertions(+), 1 deletion(-) diff --git a/tests/snippets/strings.py b/tests/snippets/strings.py index 7471b70050..7ceb653c1c 100644 --- a/tests/snippets/strings.py +++ b/tests/snippets/strings.py @@ -1,4 +1,4 @@ -from testutils import assert_raises, AssertRaises +from testutils import assert_raises, AssertRaises, skip_if_unsupported assert "".__eq__(1) == NotImplemented assert "a" == 'a' @@ -471,3 +471,73 @@ def try_mutate_str(): assert '{:e}'.format(float('inf')) == 'inf' assert '{:e}'.format(float('-inf')) == '-inf' assert '{:E}'.format(float('inf')) == 'INF' + + +# remove*fix test +def test_removeprefix(): + s='foobarfoo' + s_ref='foobarfoo' + assert s.removeprefix('f') == s_ref[1:] + assert s.removeprefix('fo') == s_ref[2:] + assert s.removeprefix('foo') == s_ref[3:] + + assert s.removeprefix('') == s_ref + assert s.removeprefix('bar') == s_ref + assert s.removeprefix('lol') == s_ref + assert s.removeprefix('_foo') == s_ref + assert s.removeprefix('-foo') == s_ref + assert s.removeprefix('afoo') == s_ref + assert s.removeprefix('*foo') == s_ref + + assert s==s_ref, 'undefined test fail' + +def test_removeprefix_types(): + s='0123456' + s_ref='0123456' + others=[0,['012']] + found=False + for o in others: + try: + s.removeprefix(o) + except: + found=True + + assert found, f'Removeprefix accepts other type: {type(o)}: {o=}' + +def test_removesuffix(): + s='foobarfoo' + s_ref='foobarfoo' + assert s.removesuffix('o') == s_ref[:-1] + assert s.removesuffix('oo') == s_ref[:-2] + assert s.removesuffix('foo') == s_ref[:-3] + + assert s.removesuffix('') == s_ref + assert s.removesuffix('bar') == s_ref + assert s.removesuffix('lol') == s_ref + assert s.removesuffix('foo_') == s_ref + assert s.removesuffix('foo-') == s_ref + assert s.removesuffix('foo*') == s_ref + assert s.removesuffix('fooa') == s_ref + + assert s==s_ref, 'undefined test fail' + +def test_removesuffix_types(): + s='0123456' + s_ref='0123456' + others=[0,6,['6']] + found=False + for o in others: + try: + s.removesuffix(o) + except: + found=True + + assert found, f'Removesuffix accepts other type: {type(o)}: {o=}' + + +skip_if_unsupported(3,9,test_removeprefix) +skip_if_unsupported(3,9,test_removeprefix_types) +skip_if_unsupported(3,9,test_removesuffix) +skip_if_unsupported(3,9,test_removesuffix_types) + + diff --git a/vm/src/obj/objstr.rs b/vm/src/obj/objstr.rs index eb3a434db8..d4579cf095 100644 --- a/vm/src/obj/objstr.rs +++ b/vm/src/obj/objstr.rs @@ -510,6 +510,22 @@ impl PyString { .to_owned() } + #[pymethod] + fn removeprefix(&self, pref: PyStringRef) -> PyResult { + if self.value.as_str().starts_with(&pref.value) { + return Ok(self.value[pref.len()..].to_string()); + } + Ok(self.value.to_string()) + } + + #[pymethod] + fn removesuffix(&self, suff: PyStringRef) -> PyResult { + if self.value.as_str().ends_with(&suff.value) { + return Ok(self.value[..self.value.len() - suff.len()].to_string()); + } + Ok(self.value.to_string()) + } + #[pymethod] fn endswith(&self, args: pystr::StartsEndsWithArgs, vm: &VirtualMachine) -> PyResult { self.value.as_str().py_startsendswith( From da09370fb6fa0043b352a14fea2d34256304d137 Mon Sep 17 00:00:00 2001 From: TheAnyKey Date: Fri, 8 May 2020 15:32:12 +0000 Subject: [PATCH 4/4] Revert "merged from TheAnyKey/p39_string_rem_pre_suffix" This reverts commit 84a6e8e8df72a7ceeb7f45781857b70ed0a7b06e. --- tests/snippets/strings.py | 72 +-------------------------------------- vm/src/obj/objstr.rs | 16 --------- 2 files changed, 1 insertion(+), 87 deletions(-) diff --git a/tests/snippets/strings.py b/tests/snippets/strings.py index 7ceb653c1c..7471b70050 100644 --- a/tests/snippets/strings.py +++ b/tests/snippets/strings.py @@ -1,4 +1,4 @@ -from testutils import assert_raises, AssertRaises, skip_if_unsupported +from testutils import assert_raises, AssertRaises assert "".__eq__(1) == NotImplemented assert "a" == 'a' @@ -471,73 +471,3 @@ def try_mutate_str(): assert '{:e}'.format(float('inf')) == 'inf' assert '{:e}'.format(float('-inf')) == '-inf' assert '{:E}'.format(float('inf')) == 'INF' - - -# remove*fix test -def test_removeprefix(): - s='foobarfoo' - s_ref='foobarfoo' - assert s.removeprefix('f') == s_ref[1:] - assert s.removeprefix('fo') == s_ref[2:] - assert s.removeprefix('foo') == s_ref[3:] - - assert s.removeprefix('') == s_ref - assert s.removeprefix('bar') == s_ref - assert s.removeprefix('lol') == s_ref - assert s.removeprefix('_foo') == s_ref - assert s.removeprefix('-foo') == s_ref - assert s.removeprefix('afoo') == s_ref - assert s.removeprefix('*foo') == s_ref - - assert s==s_ref, 'undefined test fail' - -def test_removeprefix_types(): - s='0123456' - s_ref='0123456' - others=[0,['012']] - found=False - for o in others: - try: - s.removeprefix(o) - except: - found=True - - assert found, f'Removeprefix accepts other type: {type(o)}: {o=}' - -def test_removesuffix(): - s='foobarfoo' - s_ref='foobarfoo' - assert s.removesuffix('o') == s_ref[:-1] - assert s.removesuffix('oo') == s_ref[:-2] - assert s.removesuffix('foo') == s_ref[:-3] - - assert s.removesuffix('') == s_ref - assert s.removesuffix('bar') == s_ref - assert s.removesuffix('lol') == s_ref - assert s.removesuffix('foo_') == s_ref - assert s.removesuffix('foo-') == s_ref - assert s.removesuffix('foo*') == s_ref - assert s.removesuffix('fooa') == s_ref - - assert s==s_ref, 'undefined test fail' - -def test_removesuffix_types(): - s='0123456' - s_ref='0123456' - others=[0,6,['6']] - found=False - for o in others: - try: - s.removesuffix(o) - except: - found=True - - assert found, f'Removesuffix accepts other type: {type(o)}: {o=}' - - -skip_if_unsupported(3,9,test_removeprefix) -skip_if_unsupported(3,9,test_removeprefix_types) -skip_if_unsupported(3,9,test_removesuffix) -skip_if_unsupported(3,9,test_removesuffix_types) - - diff --git a/vm/src/obj/objstr.rs b/vm/src/obj/objstr.rs index d4579cf095..eb3a434db8 100644 --- a/vm/src/obj/objstr.rs +++ b/vm/src/obj/objstr.rs @@ -510,22 +510,6 @@ impl PyString { .to_owned() } - #[pymethod] - fn removeprefix(&self, pref: PyStringRef) -> PyResult { - if self.value.as_str().starts_with(&pref.value) { - return Ok(self.value[pref.len()..].to_string()); - } - Ok(self.value.to_string()) - } - - #[pymethod] - fn removesuffix(&self, suff: PyStringRef) -> PyResult { - if self.value.as_str().ends_with(&suff.value) { - return Ok(self.value[..self.value.len() - suff.len()].to_string()); - } - Ok(self.value.to_string()) - } - #[pymethod] fn endswith(&self, args: pystr::StartsEndsWithArgs, vm: &VirtualMachine) -> PyResult { self.value.as_str().py_startsendswith(