Skip to content

Commit

Permalink
List support: copy method (#1797)
Browse files Browse the repository at this point in the history
Add support for the `copy()` method of Python lists to the semantic
stage and Python codegen. This fixes #1696.

**Commit Summary**

- Add a class representation for the `copy()` method, inheriting from
`ListMethod`. The constructor copies the attributes of the list object,
to the current object that represents the resulting new copy of the
list.
- Add check for `HomogeneousListType` in `_print_IndexedElement` to
support indexing a multidimensional list.
- Add success and error tests for the `copy()` method involving many
scenarios where the function could be used.
  • Loading branch information
Farouk-Echaref committed Mar 21, 2024
1 parent 9c08d24 commit b39fe9a
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 3 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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()`.
- #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.
- #1739 : Add Python support for set method `clear()`.
Expand All @@ -22,6 +23,7 @@ All notable changes to this project will be documented in this file.
- Allow printing the result of a function returning multiple objects of different types.
- #1792 : Fix array unpacking.
- #1795 : Fix bug when returning slices in C.
- #1732 : Fix multidimensional list indexing in Python.

### Changed
- #1720 : functions with the `@inline` decorator are no longer exposed to Python in the shared library.
Expand Down
36 changes: 36 additions & 0 deletions pyccel/ast/builtin_methods/list_methods.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

__all__ = ('ListAppend',
'ListClear',
'ListCopy',
'ListExtend',
'ListInsert',
'ListMethod',
Expand Down Expand Up @@ -270,3 +271,38 @@ def __init__(self, list_obj, removed_obj) -> None:
raise TypeError(f"Can't remove an element of type {removed_obj.class_type} from {list_obj.class_type}")
super().__init__(list_obj, removed_obj)

#==============================================================================
class ListCopy(ListMethod) :
"""
Represents a call to the .copy() method.
Represents a call to the .copy() method which is used to create a shallow
copy of a list, meaning that any modification in the new list will be
reflected in the original list.
The method returns a list.
>>> a = [1, 2, 3, 4]
>>> b = a.copy()
>>> print(a, b)
[1, 2, 3, 4]
[1, 2, 3, 4]
>>> a[0] = 0
>>> a[1] = 0
>>> print(a, b)
[0, 0, 3, 4]
[0, 0, 3, 4]
Parameters
----------
list_obj : TypedAstNode
The list object which the method is called from.
"""
__slots__ = ('_class_type', '_rank', '_shape', '_order')
name = 'copy'

def __init__(self, list_obj) -> None:
self._rank = list_obj.rank
self._shape = list_obj.shape
self._order = list_obj.order
self._class_type = list_obj.class_type
super().__init__(list_obj)
4 changes: 3 additions & 1 deletion pyccel/ast/class_defs.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@

from pyccel.ast.builtin_methods.set_methods import SetAdd, SetClear, SetCopy, SetPop, SetRemove
from pyccel.ast.builtin_methods.list_methods import (ListAppend, ListInsert, ListPop,
ListClear, ListExtend, ListRemove)
ListClear, ListExtend, ListRemove,
ListCopy)

from .builtins import PythonImag, PythonReal, PythonConjugate
from .core import ClassDef, PyccelFunctionDef
Expand Down Expand Up @@ -142,6 +143,7 @@
methods=[
PyccelFunctionDef('append', func_class = ListAppend),
PyccelFunctionDef('clear', func_class = ListClear),
PyccelFunctionDef('copy', func_class = ListCopy),
PyccelFunctionDef('extend', func_class = ListExtend),
PyccelFunctionDef('insert', func_class = ListInsert),
PyccelFunctionDef('pop', func_class = ListPop),
Expand Down
4 changes: 2 additions & 2 deletions pyccel/codegen/printing/pycode.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from pyccel.ast.builtins import PythonComplex, DtypePrecisionToCastFunction
from pyccel.ast.core import CodeBlock, Import, Assign, FunctionCall, For, AsName, FunctionAddress
from pyccel.ast.core import IfSection, FunctionDef, Module, PyccelFunctionDef
from pyccel.ast.datatypes import HomogeneousTupleType
from pyccel.ast.datatypes import HomogeneousTupleType, HomogeneousListType
from pyccel.ast.functionalexpr import FunctionalFor
from pyccel.ast.literals import LiteralTrue, LiteralString
from pyccel.ast.literals import LiteralInteger, LiteralFloat, LiteralComplex
Expand Down Expand Up @@ -284,7 +284,7 @@ def _print_IndexedElement(self, expr):
indices = indices[0]

indices = [self._print(i) for i in indices]
if expr.pyccel_staging != 'syntactic' and isinstance(expr.base.class_type, HomogeneousTupleType):
if expr.pyccel_staging != 'syntactic' and isinstance(expr.base.class_type, (HomogeneousTupleType, HomogeneousListType)):
indices = ']['.join(i for i in indices)
else:
indices = ','.join(i for i in indices)
Expand Down
29 changes: 29 additions & 0 deletions tests/epyccel/test_epyccel_lists.py
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,35 @@ def test_extend_list_class_attribute(language):
accelerated_list = modnew.fn()
assert python_list == accelerated_list

def test_copy_basic(language):
def f():
a = [1, 2, 3]
b = a.copy()
return b

epyc_f = epyccel(f, language=language)
assert f() == epyc_f()

def test_copy_nested(language):
def f():
a = [[1, 2], [3, 4]]
b = a.copy()
return b

epyc_f = epyccel(f, language=language)
assert f() == epyc_f()

def test_copy_modify_nested_values(language):
def f():
a = [[1, 2], [3, 4]]
b = a.copy()
a[0][0] = 0
a[0][1] = 0
return b

epyc_f = epyccel(f, language=language)
assert f() == epyc_f()

def test_mixed_list_methods(language):
def f():
a = [(1, 4, 5), (33, 12, 5), (3, 5)]
Expand Down

0 comments on commit b39fe9a

Please sign in to comment.