Repository: pyccel/pyccel (language: python)

Issue:
[SETS] discard : Remove the specified item
### Feature Description

**Add support for discard() method for sets in the Python translation.**
`discard(element)` : Removes an element from the set if it is a member. If the element is not a member, it does nothing.

### Test Code

This Code Should Work 

```python
my_set = {1, 2, 3}
my_set.discard(2)
print(my_set)
>>> {1, 3}
```

### Proposed Solution
See description in #1531 


Discussion / hints:

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index aeeb45cffd..c2ae1c053d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,6 +13,7 @@ All notable changes to this project will be documented in this file.
 -   #1740 : Add Python support for set method `copy()`.
 -   #1750 : Add Python support for set method `remove()`.
 -   #1787 : Ensure `STC` is installed with Pyccel.
+-   #1743 : Add Python support for set method `discard()`.
 
 ### Fixed
 
@@ -67,7 +68,7 @@ All notable changes to this project will be documented in this file.
 -   #1425 : Add support for `numpy.isnan`, `numpy.isinf` and `numpy.isfinite`.
 -   #1738 : Add Python support for creating scalar sets with `{}`.
 -   #1738 : Add Python support for set method `add`.
--   #1749 : Add Python support for set method `pop()`
+-   #1749 : Add Python support for set method `pop()`.
 
 ### Fixed
 
diff --git a/pyccel/ast/builtin_methods/set_methods.py b/pyccel/ast/builtin_methods/set_methods.py
index 81575075c3..feba49d7ff 100644
--- a/pyccel/ast/builtin_methods/set_methods.py
+++ b/pyccel/ast/builtin_methods/set_methods.py
@@ -13,8 +13,15 @@
 from pyccel.ast.internals import PyccelInternalFunction
 from pyccel.ast.basic import TypedAstNode
 
-__all__ = ('SetAdd', 'SetClear', 'SetMethod', 'SetCopy', 'SetPop', 'SetRemove')
-
+__all__ = (
+    'SetAdd',
+    'SetClear',
+    'SetCopy',
+    'SetDiscard',
+    'SetMethod',
+    'SetPop',
+    'SetRemove'
+)
 
 class SetMethod(PyccelInternalFunction):
     """
@@ -125,6 +132,7 @@ def __init__(self, set_variable):
         self._class_type = set_variable._class_type
         super().__init__(set_variable)
 
+
 class SetPop(SetMethod):
     """
     Represents a call to the .pop() method.
@@ -150,6 +158,7 @@ def __init__(self, set_variable):
         self._class_type = set_variable.class_type.element_type
         super().__init__(set_variable)
 
+
 class SetRemove(SetMethod):
     """
     Represents a call to the .remove() method.
@@ -183,3 +192,37 @@ def __init__(self, set_variable, item) -> None:
         if not is_homogeneous:
             raise TypeError(f"Can't remove an element of type {item.dtype} from a set of {set_variable.dtype}")
         super().__init__(set_variable, item)
+
+
+class SetDiscard(SetMethod):
+    """
+    Represents a call to the .discard() method.
+
+    The discard() is a built-in method to remove elements from the set.
+    The discard() method takes exactly one argument. 
+    This method does not return any value.   
+
+    Parameters
+    ----------
+    set_variable : TypedAstNode
+        The name of the set.
+
+    item : TypedAstNode
+        The item to search for, and remove.
+    """
+    __slots__ = ()
+    _shape = None
+    _order = None
+    _rank = 0
+    _class_type = VoidType()
+    name = 'discard'
+
+    def __init__(self, set_variable, item) -> None:
+        expected_type = set_variable.class_type.element_type
+        is_homogeneous = (
+            expected_type == item.class_type and
+            set_variable.rank - 1 == item.rank
+        )
+        if not is_homogeneous:
+            raise TypeError("Expecting an argument of the same type as the elements of the set")
+        super().__init__(set_variable, item)
diff --git a/pyccel/ast/class_defs.py b/pyccel/ast/class_defs.py
index c7bf31821c..2fe2f838b9 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, SetClear, SetCopy, SetPop, SetRemove
+from pyccel.ast.builtin_methods.set_methods  import SetAdd, SetClear, SetCopy, SetPop, SetRemove, SetDiscard
 from pyccel.ast.builtin_methods.list_methods import (ListAppend, ListInsert, ListPop,
                                                      ListClear, ListExtend, ListRemove,
                                                      ListCopy)
@@ -157,6 +157,7 @@
             PyccelFunctionDef('add', func_class = SetAdd ),
             PyccelFunctionDef('clear', func_class = SetClear),
             PyccelFunctionDef('copy', func_class = SetCopy),
+            PyccelFunctionDef('discard', func_class = SetDiscard),
             PyccelFunctionDef('pop', func_class = SetPop),
             PyccelFunctionDef('remove', func_class = SetRemove),
         ])


Test patch:
diff --git a/tests/epyccel/test_epyccel_sets.py b/tests/epyccel/test_epyccel_sets.py
index 574994ee0e..d467e9bdef 100644
--- a/tests/epyccel/test_epyccel_sets.py
+++ b/tests/epyccel/test_epyccel_sets.py
@@ -174,3 +174,32 @@ def remove_float():
     python_result = remove_float()
     assert python_result == pyccel_result
 
+def test_Discard_int(language):
+    def Discard_int():
+        se = {2.7, 4.3, 9.2}
+        se.discard(4.3)
+        return se
+    epyccel_remove = epyccel(Discard_int, language = language)
+    pyccel_result = epyccel_remove()
+    python_result = Discard_int()
+    assert python_result == pyccel_result
+
+def test_Discard_complex(language):
+    def Discard_complex():
+        se = {2j, 5j, 3j, 7j}
+        se.discard(5j)
+        return se
+    epyccel_remove = epyccel(Discard_complex, language = language)
+    pyccel_result = epyccel_remove()
+    python_result = Discard_complex()
+    assert python_result == pyccel_result
+
+def test_Discard_wrong_arg(language):
+    def Discard_wrong_arg():
+        se = {4.7, 1.3, 8.2}
+        se.discard(8.6)
+        return se
+    epyccel_remove = epyccel(Discard_wrong_arg, language = language)
+    pyccel_result = epyccel_remove()
+    python_result = Discard_wrong_arg()
+    assert python_result == pyccel_result
diff --git a/tests/errors/semantic/blocking/DISCARD_SET_INCOMPATIBLE_TYPES_1.py b/tests/errors/semantic/blocking/DISCARD_SET_INCOMPATIBLE_TYPES_1.py
new file mode 100644
index 0000000000..d312294181
--- /dev/null
+++ b/tests/errors/semantic/blocking/DISCARD_SET_INCOMPATIBLE_TYPES_1.py
@@ -0,0 +1,5 @@
+# pylint: disable=missing-function-docstring, missing-module-docstring
+
+a = {7, 9, 1}
+b = 2j
+a.discard(b)
diff --git a/tests/errors/semantic/blocking/DISCARD_SET_INCOMPATIBLE_TYPES_2.py b/tests/errors/semantic/blocking/DISCARD_SET_INCOMPATIBLE_TYPES_2.py
new file mode 100644
index 0000000000..e3e7e3e3ac
--- /dev/null
+++ b/tests/errors/semantic/blocking/DISCARD_SET_INCOMPATIBLE_TYPES_2.py
@@ -0,0 +1,5 @@
+# pylint: disable=missing-function-docstring, missing-module-docstring
+
+a = {5.3, 9.2, 1.7}
+b = 3
+a.discard(b)