Repository: pyccel/pyccel
Pull request #2022 (2024-10-17 15:19:36)

Activate update tests
All `update` tests seem to be working already as `update` is simply a multi-element version of `union`. This PR simply activates the existing tests and updates the documentation

pyccel-bot[bot]: Hello again! Thank you for this new pull request :star_struck:.

Please begin by requesting your checklist using the command `/bot checklist`

EmilyBourne: /bot checklist
pyccel-bot[bot]: Hey @pyccel/pyccel-dev ! @EmilyBourne has just created this great new pull request! Check it out and let me know what you think!

pyccel-bot[bot]: Unfortunately your PR is not passing the tests so it is not quite ready for review yet. Let me know when it is fixed with `/bot mark as ready`.

pyccel-bot[bot]: Hey @pyccel/pyccel-dev ! @EmilyBourne has just created this great new pull request! Check it out and let me know what you think!

pyccel-bot[bot]: Hey @pyccel/pyccel-dev ! @EmilyBourne has just created this great new pull request! Check it out and let me know what you think!

pyccel-bot[bot]: Hey @yguclu, @EmilyBourne, this PR is looking pretty good. @EmilyBourne and @jalalium think it is ready to merge. Could you add your expertise to confirm that this follows all the coding conventions and fits in Pyccel's future plans? Thanks :smile:


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 761605df..03970232 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -45,6 +45,7 @@ All notable changes to this project will be documented in this file.
 -   #1918 : Add support for set method `clear()`.
 -   #1918 : Add support for set method `copy()`.
 -   #1753 : Add support for set method `union()`.
+-   #1754 : Add support for set method `update()`.
 -   #1744 : Add Python support for set method `intersection()`.
 -   #1884 : Add support for dict method `items()`.
 -   #1936 : Add missing C output for inline decorator example in documentation
diff --git a/docs/builtin-functions.md b/docs/builtin-functions.md
index b7ca91c6..46c3e1f8 100644
--- a/docs/builtin-functions.md
+++ b/docs/builtin-functions.md
@@ -111,8 +111,8 @@ Python contains a limited number of builtin functions defined [here](https://doc
 | `remove` | Python-only |
 | `symmetric_difference` | No |
 | `symmetric_difference_update` | No |
-| **`union`** | Yes |
-| `update` | Python-only |
+| **`union`** | **Yes** |
+| **`update`** | **Yes** |
 
 ## Dictionary methods
 
diff --git a/pyccel/parser/semantic.py b/pyccel/parser/semantic.py
index dcf6b5ec..5a5c7888 100644
--- a/pyccel/parser/semantic.py
+++ b/pyccel/parser/semantic.py
@@ -5323,36 +5323,42 @@ class SemanticParser(BasicParser):
             CodeBlock or For containing SetAdd objects.
         """
         if isinstance(expr, DottedName):
-            iterable = expr.name[1].args[0].value
+            iterable_args = [a.value for a in expr.name[1].args]
             set_obj = expr.name[0]
         elif isinstance(expr, AugAssign):
-            iterable = expr.rhs
+            iterable_args = [expr.rhs]
             set_obj = expr.lhs
         else:
             raise NotImplementedError(f"Function doesn't handle {type(expr)}")
 
-        if isinstance(iterable, (PythonList, PythonSet, PythonTuple)):
-            list_variable = self._visit(set_obj)
-            added_list = self._visit(iterable)
-            try:
-                store = [SetAdd(list_variable, a) for a in added_list]
-            except TypeError as e:
-                msg = str(e)
-                errors.report(msg, symbol=expr, severity='fatal')
-            return CodeBlock(store)
+        code = []
+        for iterable in iterable_args:
+            if isinstance(iterable, (PythonList, PythonSet, PythonTuple)):
+                list_variable = self._visit(set_obj)
+                added_list = self._visit(iterable)
+                try:
+                    code.extend(SetAdd(list_variable, a) for a in added_list)
+                except TypeError as e:
+                    msg = str(e)
+                    errors.report(msg, symbol=expr, severity='fatal')
+            else:
+                pyccel_stage.set_stage('syntactic')
+                for_target = self.scope.get_new_name()
+                arg = FunctionCallArgument(for_target)
+                func_call = FunctionCall('add', [arg])
+                dotted = DottedName(set_obj, func_call)
+                lhs = PyccelSymbol('_', is_temp=True)
+                assign = Assign(lhs, dotted)
+                assign.set_current_ast(expr.python_ast)
+                body = CodeBlock([assign])
+                for_obj = For(for_target, iterable, body)
+                pyccel_stage.set_stage('semantic')
+                code.append(self._visit(for_obj))
+
+        if len(code) == 1:
+            return code[0]
         else:
-            pyccel_stage.set_stage('syntactic')
-            for_target = self.scope.get_new_name()
-            arg = FunctionCallArgument(for_target)
-            func_call = FunctionCall('add', [arg])
-            dotted = DottedName(set_obj, func_call)
-            lhs = PyccelSymbol('_', is_temp=True)
-            assign = Assign(lhs, dotted)
-            assign.set_current_ast(expr.python_ast)
-            body = CodeBlock([assign])
-            for_obj = For(for_target, iterable, body)
-            pyccel_stage.set_stage('semantic')
-            return self._visit(for_obj)
+            return CodeBlock(code)
 
     def _build_SetUnion(self, expr, function_call_args):
         """


Test patch:
diff --git a/tests/epyccel/test_epyccel_sets.py b/tests/epyccel/test_epyccel_sets.py
index 4775215b..1bd88ed4 100644
--- a/tests/epyccel/test_epyccel_sets.py
+++ b/tests/epyccel/test_epyccel_sets.py
@@ -179,14 +179,14 @@ def test_Discard_wrong_arg(python_only_language):
     python_result = Discard_wrong_arg()
     assert python_result == pyccel_result
 
-def test_update_basic(python_only_language):
+def test_update_basic(language):
     def update_basic():
         a = {1, 2, 3}
         b = {4, 5, 6}
         a.update(b)
         return len(a), a.pop(), a.pop(), a.pop(), a.pop(), a.pop(), a.pop()
 
-    epyccel_update = epyccel(update_basic, language=python_only_language)
+    epyccel_update = epyccel(update_basic, language=language)
     pyccel_result = epyccel_update()
     python_result =  update_basic()
     assert python_result[0] == pyccel_result[0]
@@ -206,6 +206,18 @@ def test_update_multiple(language):
     assert python_result[0] == pyccel_result[0]
     assert set(python_result[1:]) == set(pyccel_result[1:])
 
+def test_update_multiple_args(language):
+    def update_multiple():
+        a = {1, 2, 3}
+        a.update({4, 5}, {6, 7, 8, 9}, {10})
+        return len(a), a.pop(), a.pop(), a.pop(), a.pop(), a.pop(), a.pop(), a.pop(), a.pop(), a.pop(), a.pop()
+
+    epyccel_update = epyccel(update_multiple, language=language)
+    pyccel_result = epyccel_update()
+    python_result =  update_multiple()
+    assert python_result[0] == pyccel_result[0]
+    assert set(python_result[1:]) == set(pyccel_result[1:])
+
 
 def test_update_boolean_tuple(language):
     def update_boolean_tuple():
@@ -577,18 +589,6 @@ def test_set_intersection_operator(python_only_language):
     assert python_result[0] == pyccel_result[0]
     assert set(python_result[1:]) == set(pyccel_result[1:])
 
-@pytest.mark.parametrize( 'language', (
-        pytest.param("fortran", marks = [
-            pytest.mark.xfail(reason="Update not fully implemented yet. See #2022"),
-            pytest.mark.fortran]
-        ),
-        pytest.param("c", marks = [
-            pytest.mark.xfail(reason="Update not fully implemented yet. See #2022"),
-            pytest.mark.c]
-        ),
-        pytest.param("python", marks = pytest.mark.python)
-    )
-)
 def test_set_union_augoperator(language):
     def union_int():
         a = {1,2,3,4}