Skip to content

Commit 4fb4fa5

Browse files
authored
Ignore __all__ statements (pyccel#2100)
Fix translation of modules containing `__all__` by ignoring `__all__`. The statement is still printed in the Python translation. Fixes pyccel#2099
1 parent 6aefd21 commit 4fb4fa5

File tree

10 files changed

+79
-9
lines changed

10 files changed

+79
-9
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ All notable changes to this project will be documented in this file.
6060
- #2061 : Add C support for string declarations.
6161
- Add support for inhomogeneous tuple annotations.
6262
- #1834 : Add support for `@property` decorator.
63+
- #2099 : Fix translation of modules containing `__all__`.
6364
- \[INTERNALS\] Add abstract class `SetMethod` to handle calls to various set methods.
6465
- \[INTERNALS\] Added `container_rank` property to `ast.datatypes.PyccelType` objects.
6566
- \[INTERNALS\] Add a `__call__` method to `FunctionDef` to create `FunctionCall` instances.

pyccel/ast/core.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
# TODO [YG, 12.03.2020]: Rename classes to avoid name clashes in pyccel/ast
4242
__all__ = (
4343
'AliasAssign',
44+
'AllDeclaration',
4445
'Allocate',
4546
'AnnotatedComment',
4647
'AsName',
@@ -4404,5 +4405,36 @@ def name(self):
44044405
"""
44054406
return self._name
44064407

4408+
class AllDeclaration(PyccelAstNode):
4409+
"""
4410+
Class representing the __all__ declaration of public methods in a module.
4411+
4412+
Class representing the __all__ declaration of public methods/variables/classes
4413+
in a module.
4414+
4415+
Parameters
4416+
----------
4417+
values : iterable[LiteralString]
4418+
A PythonList/PythonTuple of strings.
4419+
"""
4420+
__slots__ = ('_values',)
4421+
_attribute_nodes = ('_values',)
4422+
4423+
def __init__(self, values):
4424+
if not hasattr(values, '__iter__') or any(not isinstance(v, LiteralString) for v in values):
4425+
errors.report("__all__ must be an iterable of strings.",
4426+
symbol=values, severity='fatal')
4427+
self._values = values
4428+
super().__init__()
4429+
4430+
@property
4431+
def values(self):
4432+
"""
4433+
An iterable of LiteralStrings describing the public methods/variables/classes/etc.
4434+
4435+
An iterable of LiteralStrings describing the public methods/variables/classes/etc.
4436+
"""
4437+
return self._values
4438+
44074439
#==============================================================================
44084440

pyccel/ast/datatypes.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -789,7 +789,11 @@ class HomogeneousListType(HomogeneousContainerType, metaclass = ArgumentSingleto
789789
def __init__(self, element_type):
790790
assert isinstance(element_type, PyccelType)
791791
if element_type.rank > 0:
792-
errors.report("Nested lists are not yet fully supported. Using containers in lists may lead to bugs such as memory leaks", symbol=self, severity="warning")
792+
# When this error is removed the pop() of the warning must also be removed
793+
# in parser/semantic.py before the creation of the AllDeclaration node
794+
errors.report("Lists of non-scalar objects are not yet fully supported. " +
795+
"Using containers in lists may lead to bugs such as memory leaks",
796+
symbol=self, severity="warning")
793797
self._element_type = element_type
794798
self._order = 'C' if (element_type.order == 'C' or element_type.rank == 1) else None
795799
super().__init__()

pyccel/codegen/printing/ccode.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2820,6 +2820,8 @@ def _print_MacroCount(self, expr):
28202820
def _print_PrecomputedCode(self, expr):
28212821
return expr.code
28222822

2823+
def _print_AllDeclaration(self, expr):
2824+
return ''
28232825

28242826
def indent_code(self, code):
28252827
"""Accepts a string of code or a list of code lines"""

pyccel/codegen/printing/fcode.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3752,5 +3752,8 @@ def _print_MacroUndef(self, expr):
37523752
name = expr.macro_name
37533753
return f'#undef {name}\n'
37543754

3755+
def _print_AllDeclaration(self, expr):
3756+
return ''
3757+
37553758
def _print_KindSpecification(self, expr):
37563759
return f'(kind = {self.print_kind(expr.type_specifier)})'

pyccel/codegen/printing/pycode.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1006,6 +1006,10 @@ def _print_Module(self, expr):
10061006
body = body,
10071007
prog = prog)
10081008

1009+
def _print_AllDeclaration(self, expr):
1010+
values = ',\n '.join(self._print(v) for v in expr.values)
1011+
return f'__all__ = ({values},)\n'
1012+
10091013
def _print_PyccelPow(self, expr):
10101014
base = self._print(expr.args[0])
10111015
e = self._print(expr.args[1])

pyccel/parser/scope.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -347,18 +347,21 @@ def insert_variable(self, var, name = None):
347347
self.insert_symbol(name)
348348

349349
def remove_variable(self, var, name = None):
350-
""" Remove a variable from anywhere in scope
350+
"""
351+
Remove a variable from anywhere in scope.
352+
353+
Remove a variable from anywhere in scope.
351354
352355
Parameters
353356
----------
354-
var : Variable
355-
The variable to be removed
356-
name : str
357+
var : Variable
358+
The variable to be removed.
359+
name : str, optional
357360
The name of the variable in the python code
358-
Default : var.name
361+
Default : var.name.
359362
"""
360363
if name is None:
361-
name = var.name
364+
name = self._original_symbol[var.name]
362365

363366
self._used_symbols.pop(name)
364367

pyccel/parser/semantic.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"""
99

1010
from itertools import chain, product
11+
import os
1112
import warnings
1213

1314
from sympy.utilities.iterables import iterable as sympy_iterable
@@ -57,6 +58,7 @@
5758
from pyccel.ast.core import Decorator
5859
from pyccel.ast.core import PyccelFunctionDef
5960
from pyccel.ast.core import Assert
61+
from pyccel.ast.core import AllDeclaration
6062

6163
from pyccel.ast.class_defs import get_cls_base
6264

@@ -1610,8 +1612,10 @@ def _assign_lhs_variable(self, lhs, d_var, rhs, new_expressions, is_augassign =
16101612

16111613
# Not yet supported for arrays: x=y+z, x=b[:]
16121614
# Because we cannot infer shape of right-hand side yet
1613-
know_lhs_shape = (lhs.rank == 0) or all(sh is not None for sh in lhs.alloc_shape) \
1614-
or isinstance(lhs.class_type, StringType)
1615+
if isinstance(lhs.dtype, StringType):
1616+
know_lhs_shape = (lhs.rank == 1) or all(sh is not None for sh in lhs.alloc_shape[:-1])
1617+
else:
1618+
know_lhs_shape = (lhs.rank == 0) or all(sh is not None for sh in lhs.alloc_shape)
16151619

16161620
if isinstance(class_type, (NumpyNDArrayType, HomogeneousTupleType)) and not know_lhs_shape:
16171621
msg = f"Cannot infer shape of right-hand side for expression {lhs} = {rhs}"
@@ -3590,6 +3594,21 @@ def _visit_Assign(self, expr):
35903594

35913595
new_expressions.append(new_expr)
35923596

3597+
if expr.lhs == '__all__':
3598+
self.scope.remove_variable(lhs[0])
3599+
self._allocs[-1].discard(lhs[0])
3600+
if isinstance(lhs[0].class_type, HomogeneousListType):
3601+
# Remove the last element of the errors (if it is a warning)
3602+
# This will be the list of list warning
3603+
try:
3604+
error_info_map = errors.error_info_map[os.path.basename(errors.target)]
3605+
if error_info_map[-1].severity == 'warning':
3606+
error_info_map.pop()
3607+
except KeyError:
3608+
# There may be a KeyError if this is not the first time that this DataType
3609+
# of list of rank>0 is created.
3610+
pass
3611+
return AllDeclaration(new_expressions[-1].rhs)
35933612

35943613
if (len(new_expressions)==1):
35953614
new_expressions = new_expressions[0]

tests/epyccel/modules/Module_1.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# pylint: disable=missing-function-docstring, missing-module-docstring
22

3+
__all__ = ('f', 'g', 'h')
34

45
def f(x : 'float [:]'):
56
x[0] = 2.

tests/epyccel/modules/Module_2.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# pylint: disable=missing-function-docstring, missing-module-docstring
22

3+
__all__ = ['f6', 'h']
34

45
def f6(m1 : 'int', m2 : 'int', x : 'float [:,:]'):
56
x[:,:] = 0.

0 commit comments

Comments
 (0)