Repository: pyccel/pyccel (python)

Issue:
clear : Removes all the elements from the set
### Feature Description

**Add support for clear() method for sets in the Python translation.**
`clear()` : Removes all elements from the set, making it empty.

### Test Code

This Code Should Work 

```python
my_set = {1, 2, 3}
my_set.clear()
```

### Proposed Solution
See description in #1531 

Pull request:
Set support : clear method
Add support for the `clear()` method of Python sets to the semantic stage.
I define an abstract class named `SetMethod` to handle calls to various set methods.
Add handling of that method to the Python printer. This fixes #1739.

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 322d037c..8ceaee09 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,9 @@ All notable changes to this project will be documented in this file.
 
 ### Added
 
+-   #1739 : Add Python support for set method `clear()`.
+-   #1739 : Add abstract class `SetMethod` to handle calls to various set methods.
+
 ### Fixed
 
 ### Changed
diff --git a/pyccel/ast/builtin_methods/set_methods.py b/pyccel/ast/builtin_methods/set_methods.py
index b5b3a076..c6626df5 100644
--- a/pyccel/ast/builtin_methods/set_methods.py
+++ b/pyccel/ast/builtin_methods/set_methods.py
@@ -12,9 +12,39 @@ This module contains objects which describe these methods within Pyccel's AST.
 from pyccel.ast.datatypes import NativeVoid, NativeGeneric
 from pyccel.ast.internals import PyccelInternalFunction
 
-__all__ = ('SetAdd',)
+__all__ = ('SetAdd', 'SetClear', 'SetMethod')
 
-class SetAdd(PyccelInternalFunction) :
+class SetMethod(PyccelInternalFunction):
+    """
+    Abstract class for set method calls.
+
+    A subclass of this base class represents calls to a specific 
+    set method.
+
+    Parameters
+    ----------
+    set_variable : TypedAstNode
+        The set on which the method will operate.
+
+    *args : iterable
+        The arguments passed to the function call.
+    """
+    __slots__ = ('_set_variable',)
+    _attribute_nodes = ('_set_variable',)
+    def __init__(self,  set_variable, *args):
+        self._set_variable = set_variable
+        super().__init__(*args)
+
+    @property
+    def set_variable(self):
+        """
+        Get the variable representing the set.
+
+        Get the variable representing the set.
+        """
+        return self._set_variable
+
+class SetAdd(SetMethod) :
     """
     Represents a call to the .add() method.
     
@@ -25,13 +55,12 @@ class SetAdd(PyccelInternalFunction) :
     Parameters
     ----------
     set_variable : TypedAstNode
-        The name of the set.
+        The set on which the method will operate.
 
     new_elem : TypedAstNode
         The element that needs to be added to a set.
     """
-    __slots__ = ("_set_variable", "_add_arg")
-    _attribute_nodes = ("_set_variable", "_add_arg")
+    __slots__ = ()
     _dtype = NativeVoid()
     _shape = None
     _order = None
@@ -50,24 +79,28 @@ class SetAdd(PyccelInternalFunction) :
         )
         if not is_homogeneous:
             raise TypeError("Expecting an argument of the same type as the elements of the set")
-        self._set_variable = set_variable
-        self._add_arg = new_elem
-        super().__init__()
+        super().__init__(set_variable, new_elem)
 
-    @property
-    def set_variable(self):
-        """
-        Get the variable representing the set.
-
-        Get the variable representing the set.
-        """
-        return self._set_variable
+class SetClear(SetMethod):
+    """
+    Represents a call to the .clear() method.
+    
+    The method clear is used to remove all data from a set. 
+    This operation clears all elements from the set, leaving it empty.
 
-    @property
-    def add_argument(self):
-        """
-        Get the argument which is passed to add().
+    Parameters
+    ----------
+    set_variable : TypedAstNode
+        The set on which the method will operate.
+    """
+    __slots__ = ()
+    _dtype = NativeVoid()
+    _shape = None
+    _order = None
+    _rank = 0
+    _precision = None
+    _class_type = NativeVoid()
+    name = 'clear'
 
-        Get the argument which is passed to add().
-        """
-        return self._add_arg
+    def __init__(self, set_variable):
+        super().__init__(set_variable)
diff --git a/pyccel/ast/class_defs.py b/pyccel/ast/class_defs.py
index 250d4618..ecb09b2f 100644
--- a/pyccel/ast/class_defs.py
+++ b/pyccel/ast/class_defs.py
@@ -6,7 +6,7 @@
 This module contains all types which define a python class which is automatically recognised by pyccel
 """
 
-from pyccel.ast.builtin_methods.set_methods import SetAdd
+from pyccel.ast.builtin_methods.set_methods import SetAdd, SetClear
 from pyccel.ast.builtin_methods.list_methods import ListAppend, ListInsert, ListPop, ListClear
 
 
@@ -155,6 +155,8 @@ SetClass = ClassDef('set', class_type=NativeHomogeneousSet(),
         methods=[
             PyccelFunctionDef('add', func_class = SetAdd,
                 decorators = {}),
+            PyccelFunctionDef('clear', func_class = SetClear,
+                decorators={}),
         ])
 
 #=======================================================================================
diff --git a/pyccel/codegen/printing/pycode.py b/pyccel/codegen/printing/pycode.py
index b70d6727..fabdabc3 100644
--- a/pyccel/codegen/printing/pycode.py
+++ b/pyccel/codegen/printing/pycode.py
@@ -884,10 +884,12 @@ class PythonCodePrinter(CodePrinter):
                 stop  = stop,
                 step  = step)
 
-    def _print_SetAdd(self, expr):
-        name = self._print(expr.set_variable)
-        args = self._print(expr.add_argument)
-        return f"{name}.add({args})\n"
+    def _print_SetMethod(self, expr):
+        set_var = self._print(expr.set_variable)
+        name = expr.name
+        args = "" if len(expr.args) == 0 or expr.args[-1] is None \
+            else ', '.join(self._print(a) for a in expr.args)
+        return f"{set_var}.{name}({args})\n"
 
     def _print_Nil(self, expr):
         return 'None'


Test patch:
diff --git a/tests/epyccel/test_epyccel_sets.py b/tests/epyccel/test_epyccel_sets.py
index 78ff9057..4d838911 100644
--- a/tests/epyccel/test_epyccel_sets.py
+++ b/tests/epyccel/test_epyccel_sets.py
@@ -46,3 +46,34 @@ def test_add_variable_int(language):
     pyccel_result = epyc_add_element()
     python_result = add_element_range()
     assert python_result == pyccel_result
+
+def test_clear_int(language):
+    def clear_int():
+        se = {1,2,4,5}
+        se.clear()
+        return se
+    epyccel_clear = epyccel(clear_int, language = language)
+    pyccel_result = epyccel_clear()
+    python_result = clear_int()
+    assert python_result == pyccel_result
+
+def test_clear_float(language):
+    def clear_float():
+        se = {7.2, 2.1, 9.8, 6.4}
+        se.clear()
+        return se
+    epyccel_clear = epyccel(clear_float, language = language)
+    pyccel_result = epyccel_clear()
+    python_result = clear_float()
+    assert python_result == pyccel_result
+
+def test_clear_complex(language):
+    def clear_complex():
+        se = {3j, 6j, 2j}
+        se.clear()
+        return se
+    epyccel_clear = epyccel(clear_complex, language = language)
+    pyccel_result = epyccel_clear()
+    python_result = clear_complex()
+    assert python_result == pyccel_result
+