Skip to content

Commit eb9b7f6

Browse files
authored
Remove deprecated type specifiers in tests (pyccel#2124)
Remove deprecated type specifiers in tests. This is part of phase 2 of pyccel#1487 . Tests using global templates were changed to use `TypeAlias` variables. This highlighted some remaining bugs with this method which have been fixed. There are still some files remaining which contain headers. These are either related to macros or related to pyccel#1358 . ## Commit Summary - Add a static type to `PythonType` to allow the use of `a : type = int` instead of `a : TypeAlias = int` which is valid in all Python versions - Add a pickling function for `NumpyNDArrayType` - Add default arguments in `__new__` methods to avoid the need for pickling functions - Ensure a `BitOr` can be used in a `TypeAlias` (`a : TypeAlias = int | float`) - Allow a string to be used as a `TypeAlias` (to match syntax used elsewhere and to allow `TypeAlias` objects to be compatible with all Python versions) - Ensure types such as `'T[:]'` or `'tuple[T, bool]'` are properly handled if `T` is a `TypeAlias` - Remove tests related only to header syntax - Use `TypeAlias` instead of global templates - Remove use of `@types` decorator ## Remaining files containing deprecated type hints - codegen/fcode/scripts/macros.py - codegen/fcode/scripts/decorators.py - codegen/fcode/scripts/functions_inout.py - codegen/fcode/scripts/headers.py - codegen/fcode/scripts/returns.py - codegen/fcode/scripts/multiple_assign.py - codegen/fcode/scripts/matrix_mul.py - codegen/fcode/scripts/Functional_Stmts.py - codegen/fcode/scripts/loops.py - codegen/ccode/scripts/functions.py - errors/known_bugs/header_interface.py - macro/scripts/blas/runtest_dswap.py - macro/scripts/blas/runtest_dscal.py - macro/scripts/blas/runtest_dger.py - macro/scripts/blas/runtest_dgemv.py - macro/scripts/blas/bugs/dnrm2.py - macro/scripts/blas/runtest_dcopy.py - macro/scripts/blas/runtest_daxpy.py - macro/scripts/blas/runtest_dgemm.py - macro/scripts/lapack/runtest_dgbtrf.py - macro/scripts/MPI/mpi4py.py
1 parent 804d153 commit eb9b7f6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+259
-618
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ All notable changes to this project will be documented in this file.
6262
- #1834 : Add support for `@property` decorator.
6363
- #2099 : Fix translation of modules containing `__all__`.
6464
- #983 : Add support for built-in function `round`.
65+
- Add support for `type` as a type annotation.
6566
- \[INTERNALS\] Add abstract class `SetMethod` to handle calls to various set methods.
6667
- \[INTERNALS\] Added `container_rank` property to `ast.datatypes.PyccelType` objects.
6768
- \[INTERNALS\] Add a `__call__` method to `FunctionDef` to create `FunctionCall` instances.
@@ -97,6 +98,7 @@ All notable changes to this project will be documented in this file.
9798
- #2085 : Fix calling class methods before they are defined.
9899
- #2111 : Fix declaration of class attributes with name conflicts using type annotations.
99100
- #2115 : Fix integer handling with NumPy 2.0 on Windows.
101+
- Fix handling of union `typing.TypeAlias` objects as type hints.
100102

101103
### Changed
102104

pyccel/ast/builtins.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
from .datatypes import HomogeneousTupleType, InhomogeneousTupleType
2222
from .datatypes import HomogeneousListType, HomogeneousContainerType
2323
from .datatypes import FixedSizeNumericType, HomogeneousSetType, SymbolicType
24-
from .datatypes import DictType, VoidType
24+
from .datatypes import DictType, VoidType, TypeAlias
2525
from .internals import PyccelFunction, Slice, PyccelArrayShapeElement, Iterable
2626
from .literals import LiteralInteger, LiteralFloat, LiteralComplex, Nil
2727
from .literals import Literal, LiteralImaginaryUnit, convert_to_literal
@@ -1586,6 +1586,7 @@ class PythonType(PyccelFunction):
15861586
_attribute_nodes = ('_obj',)
15871587
_class_type = SymbolicType()
15881588
_shape = None
1589+
_static_type = TypeAlias()
15891590

15901591
def __init__(self, obj):
15911592
if not isinstance (obj, TypedAstNode):

pyccel/ast/numpytypes.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,22 @@ def __eq__(self, other):
432432
return isinstance(other, NumpyNDArrayType) and self.element_type == other.element_type \
433433
and self.rank == other.rank and self.order == other.order
434434

435+
def __reduce__(self):
436+
"""
437+
Function called during pickling.
438+
439+
For more details see : https://docs.python.org/3/library/pickle.html#object.__reduce__.
440+
This function is necessary to ensure that DataTypes remain singletons.
441+
442+
Returns
443+
-------
444+
callable
445+
A callable to create the object.
446+
args
447+
A tuple containing any arguments to be passed to the callable.
448+
"""
449+
return (self.__class__, (self._element_type, self._container_rank, self._order))
450+
435451
#==============================================================================
436452

437453
numpy_precision_map = {

pyccel/ast/operators.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -615,7 +615,7 @@ class PyccelAdd(PyccelArithmeticOperator):
615615
__slots__ = ()
616616
_precedence = 12
617617

618-
def __new__(cls, arg1, arg2, simplify = False):
618+
def __new__(cls, arg1 = None, arg2 = None, simplify = False):
619619
if simplify:
620620
if isinstance(arg2, PyccelUnarySub):
621621
return PyccelMinus(arg1, arg2.args[0], simplify = True)
@@ -699,7 +699,7 @@ class PyccelMul(PyccelArithmeticOperator):
699699
__slots__ = ()
700700
_precedence = 13
701701

702-
def __new__(cls, arg1, arg2, simplify = False):
702+
def __new__(cls, arg1 = None, arg2 = None, simplify = False):
703703
if simplify:
704704
if (arg1 == 1):
705705
return arg2
@@ -749,7 +749,7 @@ class PyccelMinus(PyccelArithmeticOperator):
749749
__slots__ = ()
750750
_precedence = 12
751751

752-
def __new__(cls, arg1, arg2, simplify = False):
752+
def __new__(cls, arg1 = None, arg2 = None, simplify = False):
753753
if simplify:
754754
if isinstance(arg2, PyccelUnarySub):
755755
return PyccelAdd(arg1, arg2.args[0], simplify = True)
@@ -799,7 +799,7 @@ class PyccelDiv(PyccelArithmeticOperator):
799799
__slots__ = ()
800800
_precedence = 13
801801

802-
def __new__(cls, arg1, arg2, simplify=False):
802+
def __new__(cls, arg1 = None, arg2 = None, simplify=False):
803803
if simplify:
804804
if (arg2 == 1):
805805
return arg1
@@ -975,7 +975,7 @@ class PyccelEq(PyccelComparisonOperator):
975975
__slots__ = ()
976976
op = "=="
977977

978-
def __new__(cls, arg1, arg2, simplify = False):
978+
def __new__(cls, arg1 = None, arg2 = None, simplify = False):
979979
if isinstance(arg1, Nil) or isinstance(arg2, Nil):
980980
return PyccelIs(arg1, arg2)
981981
else:
@@ -1007,7 +1007,7 @@ class PyccelNe(PyccelComparisonOperator):
10071007
__slots__ = ()
10081008
op = "!="
10091009

1010-
def __new__(cls, arg1, arg2, simplify = False):
1010+
def __new__(cls, arg1 = None, arg2 = None, simplify = False):
10111011
if isinstance(arg1, Nil) or isinstance(arg2, Nil):
10121012
return PyccelIsNot(arg1, arg2)
10131013
else:

pyccel/ast/type_annotations.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
from .basic import PyccelAstNode
1313

14+
from .bitwise_operators import PyccelBitOr
15+
1416
from .core import FunctionDefArgument
1517

1618
from .datatypes import PythonNativeBool, PythonNativeInt, PythonNativeFloat, PythonNativeComplex
@@ -255,17 +257,24 @@ class SyntacticTypeAnnotation(PyccelAstNode):
255257
256258
Parameters
257259
----------
258-
dtype : PyccelSymbol | IndexedElement | DottedName
260+
dtype : str | IndexedElement | DottedName
259261
The dtype named in the type annotation.
260262
261263
order : str | None
262264
The order requested in the type annotation.
263265
"""
264266
__slots__ = ('_dtype', '_order')
265267
_attribute_nodes = ('_dtype',)
268+
269+
def __new__(cls, dtype = None, order = None):
270+
if isinstance(dtype, PyccelBitOr):
271+
return UnionTypeAnnotation(*[SyntacticTypeAnnotation(d) for d in dtype.args])
272+
else:
273+
return super().__new__(cls)
274+
266275
def __init__(self, dtype, order = None):
267276
if not isinstance(dtype, (str, DottedName, IndexedElement)):
268-
raise ValueError("Syntactic datatypes should be strings")
277+
raise ValueError("Syntactic datatypes should be strings not {type(dtype)}")
269278
if not (order is None or isinstance(order, str)):
270279
raise ValueError("Order should be a string")
271280
self._dtype = dtype

pyccel/parser/semantic.py

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
from sympy import Integer as sp_Integer
1919
from sympy import ceiling
2020

21+
from textx.exceptions import TextXSyntaxError
22+
2123
#==============================================================================
2224
from pyccel.utilities.strings import random_string
2325
from pyccel.ast.basic import PyccelAstNode, TypedAstNode, ScopedAstNode
@@ -139,6 +141,7 @@
139141

140142
from pyccel.parser.base import BasicParser
141143
from pyccel.parser.syntactic import SyntaxParser
144+
from pyccel.parser.syntax.headers import types_meta
142145

143146
from pyccel.utilities.stage import PyccelStage
144147

@@ -922,6 +925,12 @@ def _create_PyccelOperator(self, expr, visited_args):
922925
The new operator.
923926
"""
924927
arg1 = visited_args[0]
928+
if isinstance(arg1, FunctionDef):
929+
msg = ("Function found in a mathematical operation. "
930+
"Are you trying to declare a type? "
931+
"If so then the type object must be used as a type hint.")
932+
errors.report(msg,
933+
severity='fatal', symbol=expr)
925934
class_type = arg1.class_type
926935
class_base = self.scope.find(str(class_type), 'classes') or get_cls_base(class_type)
927936
magic_method_name = magic_method_map.get(type(expr), None)
@@ -3289,10 +3298,19 @@ def _visit_Assign(self, expr):
32893298
lhs = lhs.name
32903299

32913300
if semantic_lhs_var.class_type is TypeAlias():
3292-
if not isinstance(rhs, SyntacticTypeAnnotation):
3293-
pyccel_stage.set_stage('syntactic')
3301+
pyccel_stage.set_stage('syntactic')
3302+
if isinstance(rhs, LiteralString):
3303+
try:
3304+
annotation = types_meta.model_from_str(rhs.python_value)
3305+
except TextXSyntaxError as e:
3306+
errors.report(f"Invalid header. {e.message}",
3307+
symbol = expr, severity = 'fatal')
3308+
rhs = annotation.expr
3309+
rhs.set_current_ast(expr.python_ast)
3310+
elif not isinstance(rhs, (SyntacticTypeAnnotation, FunctionTypeAnnotation,
3311+
VariableTypeAnnotation, UnionTypeAnnotation)):
32943312
rhs = SyntacticTypeAnnotation(rhs)
3295-
pyccel_stage.set_stage('semantic')
3313+
pyccel_stage.set_stage('semantic')
32963314
type_annot = self._visit(rhs)
32973315
self.scope.insert_symbolic_alias(lhs, type_annot)
32983316
return EmptyNode()
@@ -4154,26 +4172,37 @@ def unpack(ann):
41544172
templates = {t: v for t,v in templates.items() if t in used_type_names}
41554173

41564174
# Create new temparary templates for the arguments with a Union data type.
4157-
pyccel_stage.set_stage('syntactic')
41584175
tmp_templates = {}
41594176
new_expr_args = []
41604177
for a in expr.arguments:
4161-
if isinstance(a.annotation, UnionTypeAnnotation):
4162-
annotation = [aa for a in a.annotation for aa in unpack(a)]
4178+
annot = a.annotation
4179+
if isinstance(annot, UnionTypeAnnotation):
4180+
annotation = [aa for a in annot for aa in unpack(a)]
4181+
elif isinstance(annot, SyntacticTypeAnnotation):
4182+
elem = annot.dtype
4183+
if isinstance(elem, IndexedElement):
4184+
elem = [elem.base] + [a.dtype for a in elem.indices if isinstance(a, SyntacticTypeAnnotation)]
4185+
else:
4186+
elem = [elem]
4187+
if all(e not in templates for e in elem):
4188+
annotation = unpack(self._visit(annot))
4189+
else:
4190+
annotation = [annot]
41634191
else:
4164-
annotation = [a.annotation]
4192+
annotation = [annot]
41654193
if len(annotation)>1:
41664194
tmp_template_name = a.name + '_' + random_string(12)
41674195
tmp_template_name = self.scope.get_new_name(tmp_template_name)
4196+
pyccel_stage.set_stage('syntactic')
41684197
tmp_templates[tmp_template_name] = UnionTypeAnnotation(*[self._visit(vi) for vi in annotation])
41694198
dtype_symb = PyccelSymbol(tmp_template_name, is_temp=True)
41704199
dtype_symb = SyntacticTypeAnnotation(dtype_symb)
41714200
var_clone = AnnotatedPyccelSymbol(a.var.name, annotation=dtype_symb, is_temp=a.var.name.is_temp)
41724201
new_expr_args.append(FunctionDefArgument(var_clone, bound_argument=a.bound_argument,
41734202
value=a.value, kwonly=a.is_kwonly, annotation=dtype_symb))
4203+
pyccel_stage.set_stage('semantic')
41744204
else:
41754205
new_expr_args.append(a)
4176-
pyccel_stage.set_stage('semantic')
41774206

41784207
templates.update(tmp_templates)
41794208
template_combinations = list(product(*[v.type_list for v in templates.values()]))

tests/epyccel/classes/class_headers.py

Lines changed: 0 additions & 16 deletions
This file was deleted.

tests/epyccel/modules/Module_9.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# pylint: disable=missing-function-docstring, missing-module-docstring
22
from typing import TypeAlias
33

4-
MyType : TypeAlias = float
4+
MyType : TypeAlias = float | int #pylint: disable=unsupported-binary-operation
55

66
def set_i(x : 'MyType[:]', i : 'int', val : MyType):
77
x[i] = val

tests/epyccel/modules/generic_functions.py

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,30 @@
11
# pylint: disable=missing-function-docstring, missing-module-docstring
22
from pyccel.decorators import template
33

4-
#$ header function gen_2(real, int)
5-
#$ header function gen_2(int, real)
6-
#$ header function gen_4(T, T)
7-
#$ header template T(int|real)
8-
#$ header template R(int|real)
9-
#$ header template O(real|complex)
10-
#$ header template S(int|real|complex)
4+
T : type = 'int | float'
5+
R : type = 'int | float'
6+
O : type = 'float | complex'
7+
S : type = 'int | float | complex'
118

129
def gen_1(a : 'float'):
1310
return a / 10
1411

15-
def gen_2(y, x):
12+
def gen_2(y : 'float | int', x : 'int | float'):
1613
return y / x
1714

18-
def gen_3(x : 'T', y : 'T'):
15+
def gen_3(x : T, y : T):
1916
return x / y
2017

21-
def gen_4(x, y):
18+
def gen_4(x : T, y : T):
2219
return x / y
2320

24-
def gen_5(x : 'T', y : 'R'):
21+
def gen_5(x : T, y : R):
2522
return x / y
2623

27-
def gen_6(x : 'S', y : 'S'):
24+
def gen_6(x : S, y : S):
2825
return x + y
2926

30-
def gen_7(x : 'T', y : 'T', z : 'R'):
27+
def gen_7(x : T, y : T, z : R):
3128
return x + y + z
3229

3330

@@ -41,7 +38,7 @@ def local_overide_1(x : 'O', y : 'O'):
4138
return x + y
4239

4340
@template('Z', types=['int', 'real'])
44-
def tmplt_tmplt_1(x : 'Z', y : 'Z', z : 'R'):
41+
def tmplt_tmplt_1(x : 'Z', y : 'Z', z : R):
4542
return x + y + z
4643

4744
def tst_gen_1():

tests/epyccel/modules/generic_functions_2.py

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,7 @@ def tmplt_1(x : 'Z', y : 'Z'):
1111
def multi_tmplt_1(x : 'Z', y : 'Z', z : 'Y'):
1212
return x + y + z
1313

14-
@types('int', 'int')
15-
@types('int', 'float')
16-
def multi_heads_1(x, y):
14+
def multi_heads_1(x : int, y : 'int | float'):
1715
return x + y
1816

1917
@template(types=['int', 'float'], name = 'Z')
@@ -46,9 +44,7 @@ def default_var_3(x : 'G', y : 'K' = False):
4644
return x
4745
return x - 1
4846

49-
@types('int', 'int')
50-
@types('float', 'int')
51-
def default_var_4(x, y = 5):
47+
def default_var_4(x : 'int | float', y : int = 5):
5248
return x + y
5349

5450

@@ -67,17 +63,13 @@ def optional_var_2(x : 'G', y : 'K' = None):
6763
return x + 1j
6864
return x + y
6965

70-
@types('int', 'float')
71-
@types('float', 'float')
72-
def optional_var_3(x, y = None):
66+
def optional_var_3(x : 'int | float', y : float = None):
7367
if y is None:
7468
return x / 2.0
7569
return x / y
7670

7771

78-
@types('complex', 'int')
79-
@types('float', 'int')
80-
def optional_var_4(x, y = None):
72+
def optional_var_4(x : 'complex | float', y : int = None):
8173
if y is None:
8274
return x
8375
return x + y
@@ -130,9 +122,7 @@ def mix_array_1(x : 'T', a : 'int'):
130122
x[:] += a
131123

132124

133-
@types('complex[:]', 'complex[:]', 'int')
134-
@types('float[:]', 'int64[:]', 'int')
135-
def mix_array_2(x, y, a):
125+
def mix_array_2(x : 'complex[:] | float[:]', y : 'complex[:] | int64[:]', a : int):
136126
x[:] += a
137127
y[:] -= a
138128

0 commit comments

Comments
 (0)