Repository: pyccel/pyccel (python)

Issue:
 sort: sort a list in ascending, descending, or user-defined order.
### Feature Description

Add support for sort() method for lists in the Python translation.

### Test Code

This Code Should Work 

```python
prime_numbers = [11, 3, 7, 5, 2]

prime_numbers.sort()

print(prime_numbers)

>> [2, 3, 5, 7, 11]
```


### Proposed Solution
See description in #1529

Pull request description:
List support: `sort` method
Add support for the `sort()` method of Python lists to the semantic stage and Python codegen. This fixes #1700 .

**Commit Summary**

- Add a class representation for the `sort()` method, inheriting from `ListMethod`. The constructor checks the passing arguments, and raises an error if the method has an an optional argument.
- Add success and error tests for the `sort()` method involving scenarios where the function could be used.

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 40022055..4f5fa66c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file.
 ### Added
 -   #1720 : Add support for `Ellipsis` as the only index for an array.
 -   #1694 : Add Python support for list method `extend()`.
+-   #1700 : Add Python support for list method `sort()`.
 -   #1696 : Add Python support for list method `copy()`.
 -   #1693 : Add Python support for list method `remove()`.
 -   #1739 : Add abstract class `SetMethod` to handle calls to various set methods.
diff --git a/pyccel/ast/builtin_methods/list_methods.py b/pyccel/ast/builtin_methods/list_methods.py
index 6e59e39c..462e27cb 100644
--- a/pyccel/ast/builtin_methods/list_methods.py
+++ b/pyccel/ast/builtin_methods/list_methods.py
@@ -21,6 +21,7 @@ __all__ = ('ListAppend',
            'ListMethod',
            'ListPop',
            'ListRemove',
+           'ListSort',
            )
 
 #==============================================================================
@@ -279,3 +280,42 @@ class ListCopy(ListMethod) :
         self._shape = list_obj.shape
         self._class_type = list_obj.class_type
         super().__init__(list_obj)
+
+#==============================================================================
+class ListSort(ListMethod) :
+    """
+    Represents a call to the .sort() method.
+
+    Represents a call to the `.sort()` method, which sorts the elements of the
+    list in ascending order and modifies the original list in place. This means
+    that the elements of the original list are rearranged to be in sorted order.
+    Optional parameters are not supported, therefore they should not be provided. 
+    Note that the .sort() method doesn't return any value.
+    
+    >>> a = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
+    >>> a.sort()
+    >>> print(a)
+    [1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 9]
+
+    Parameters
+    ----------
+    list_obj : TypedAstNode
+        The list object which the method is called from.
+
+    reverse : TypedAstNode, optional
+        Argument mimicking sort's reverse parameter. This argument is 
+        unsupported so it should not be provided.
+
+    key : FunctionDef, optional
+        A function to specify the sorting criteria(s). This argument is 
+        unsupported so it should not be provided.
+    """
+    __slots__ = ()
+    _shape = None
+    _class_type = VoidType()
+    name = 'sort'
+
+    def __init__(self, list_obj, reverse=None, key=None) -> None:
+        if reverse is not None or key is not None:
+            raise TypeError("Optional Parameters are not supported for sort() method.")
+        super().__init__(list_obj, reverse, key)
diff --git a/pyccel/ast/class_defs.py b/pyccel/ast/class_defs.py
index 2fe2f838..a09a754d 100644
--- a/pyccel/ast/class_defs.py
+++ b/pyccel/ast/class_defs.py
@@ -9,7 +9,7 @@ This module contains all types which define a python class which is automaticall
 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)
+                                                     ListCopy, ListSort)
 
 from .builtins   import PythonImag, PythonReal, PythonConjugate
 from .core       import ClassDef, PyccelFunctionDef
@@ -147,6 +147,7 @@ ListClass = ClassDef('list',
             PyccelFunctionDef('extend', func_class = ListExtend),
             PyccelFunctionDef('insert', func_class = ListInsert),
             PyccelFunctionDef('pop', func_class = ListPop),
+            PyccelFunctionDef('sort', func_class = ListSort),
             PyccelFunctionDef('remove', func_class = ListRemove),
         ])
 


Test patch:
diff --git a/tests/epyccel/test_epyccel_lists.py b/tests/epyccel/test_epyccel_lists.py
index 05b48bc6..5fe655cd 100644
--- a/tests/epyccel/test_epyccel_lists.py
+++ b/tests/epyccel/test_epyccel_lists.py
@@ -476,6 +476,33 @@ def test_extend_function_return(language):
     epyc_f = epyccel(f, language=language)
     assert f() == epyc_f()
 
+def test_sort_basic(language):
+    def f():
+        a = [4, 0, 1, -1]
+        a.sort()
+        return a
+
+    epyc_f = epyccel(f, language=language)
+    assert f() == epyc_f()
+
+def test_sort_bool(language):
+    def f():
+        a = [True, False, False, True, False]
+        a.sort()
+        return a
+
+    epyc_f = epyccel(f, language=language)
+    assert f() == epyc_f()
+
+def test_sort_float(language):
+    def f():
+        a = [3.4, 1.0, -4.5, 0.0, 2.1]
+        a.sort()
+        return a
+
+    epyc_f = epyccel(f, language=language)
+    assert f() == epyc_f()
+
 def test_extend_list_as_arg(language):
     def f():
         a = [1, 2, 3]
diff --git a/tests/errors/semantic/blocking/SORT_LIST_OPTIONAL_PARAM.py b/tests/errors/semantic/blocking/SORT_LIST_OPTIONAL_PARAM.py
new file mode 100644
index 00000000..21c61dcb
--- /dev/null
+++ b/tests/errors/semantic/blocking/SORT_LIST_OPTIONAL_PARAM.py
@@ -0,0 +1,5 @@
+# pylint: disable=missing-function-docstring, missing-module-docstring
+
+a = [1, 2, -3, -4, 5]
+a.sort(reverse=True, key=abs)
+