From ea326951cdf72a2833501fcab01e362a10313088 Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Fri, 6 Oct 2023 22:09:04 +0200 Subject: [PATCH 01/44] Trying Python 3.12 --- .github/workflows/general-ci.yml | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/general-ci.yml b/.github/workflows/general-ci.yml index 138726ef1d..063c1f3e7d 100644 --- a/.github/workflows/general-ci.yml +++ b/.github/workflows/general-ci.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.7,'3.11'] + python-version: [3.7,'3.12'] simplify: [0,1,autoopt] steps: diff --git a/setup.py b/setup.py index 6f97086543..a0ac2e2d49 100644 --- a/setup.py +++ b/setup.py @@ -63,7 +63,7 @@ "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", ], - python_requires='>=3.6, <3.12', + python_requires='>=3.6, <3.13', packages=find_packages(exclude=["*.tests", "*.tests.*", "tests.*", "tests"]), package_data={ '': [ From 6a320d1b0cfca3ce2588399acc3786aac9db794e Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Sat, 7 Oct 2023 12:11:04 +0200 Subject: [PATCH 02/44] Preparing for deprecation. --- dace/frontend/python/newast.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/dace/frontend/python/newast.py b/dace/frontend/python/newast.py index 0329e31641..71d834e955 100644 --- a/dace/frontend/python/newast.py +++ b/dace/frontend/python/newast.py @@ -49,6 +49,11 @@ Shape = Union[ShapeTuple, ShapeList] DependencyType = Dict[str, Tuple[SDFGState, Union[Memlet, nodes.Tasklet], Tuple[int]]] +if sys.version_info < (3, 8): + _simple_ast_nodes = (ast.Constant, ast.Name, ast.NameConstant, ast.Num) +else: + _simple_ast_nodes = (ast.Constant, ast.Name) + class SkipCall(Exception): """ Exception used to skip calls to functions that cannot be parsed. """ @@ -2344,12 +2349,11 @@ def _is_test_simple(self, node: ast.AST): # Fix for scalar promotion tests # TODO: Maybe those tests should use the SDFG API instead of the # Python frontend which can change how it handles conditions. - simple_ast_nodes = (ast.Constant, ast.Name, ast.NameConstant, ast.Num) - is_test_simple = isinstance(node, simple_ast_nodes) + is_test_simple = isinstance(node, _simple_ast_nodes) if not is_test_simple: if isinstance(node, ast.Compare): - is_left_simple = isinstance(node.left, simple_ast_nodes) - is_right_simple = (len(node.comparators) == 1 and isinstance(node.comparators[0], simple_ast_nodes)) + is_left_simple = isinstance(node.left, _simple_ast_nodes) + is_right_simple = (len(node.comparators) == 1 and isinstance(node.comparators[0], _simple_ast_nodes)) if is_left_simple and is_right_simple: return True elif isinstance(node, ast.BoolOp): From b6f56d56c1c901c48ad5111e7ed95565d6a5d4eb Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Sat, 7 Oct 2023 12:11:27 +0200 Subject: [PATCH 03/44] Fixed assertEqual(s) call. --- tests/transformations/move_loop_into_map_test.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/transformations/move_loop_into_map_test.py b/tests/transformations/move_loop_into_map_test.py index 67c60c01bf..dca775bb7a 100644 --- a/tests/transformations/move_loop_into_map_test.py +++ b/tests/transformations/move_loop_into_map_test.py @@ -96,17 +96,17 @@ def test_multiple_edges(self): def test_itervar_in_map_range(self): sdfg = should_not_apply_1.to_sdfg(simplify=True) count = sdfg.apply_transformations(MoveLoopIntoMap) - self.assertEquals(count, 0) + self.assertEqual(count, 0) def test_itervar_in_data(self): sdfg = should_not_apply_2.to_sdfg(simplify=True) count = sdfg.apply_transformations(MoveLoopIntoMap) - self.assertEquals(count, 0) + self.assertEqual(count, 0) def test_non_injective_index(self): sdfg = should_not_apply_3.to_sdfg(simplify=True) count = sdfg.apply_transformations(MoveLoopIntoMap) - self.assertEquals(count, 0) + self.assertEqual(count, 0) def test_apply_multiple_times(self): sdfg = apply_multiple_times.to_sdfg(simplify=True) From dcbfd2a7e51e631a36bd9f7559289c5eb1e5cb3a Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Sat, 7 Oct 2023 13:49:11 +0200 Subject: [PATCH 04/44] Reworked code to avoid deprecation warnings and errors. --- dace/frontend/python/astutils.py | 41 ++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/dace/frontend/python/astutils.py b/dace/frontend/python/astutils.py index faf214fdeb..ff2d191752 100644 --- a/dace/frontend/python/astutils.py +++ b/dace/frontend/python/astutils.py @@ -15,6 +15,12 @@ from dace import dtypes, symbolic +if sys.version_info >= (3, 8): + NumConstant = ast.Constant +else: + NumConstant = ast.Num + + def _remove_outer_indentation(src: str): """ Removes extra indentation from a source Python function. @@ -66,8 +72,9 @@ def is_constant(node: ast.AST) -> bool: if sys.version_info >= (3, 8): if isinstance(node, ast.Constant): return True - if isinstance(node, (ast.Num, ast.Str, ast.NameConstant)): # For compatibility - return True + else: + if isinstance(node, (ast.Num, ast.Str, ast.NameConstant)): # For compatibility + return True return False @@ -82,13 +89,14 @@ def evalnode(node: ast.AST, gvars: Dict[str, Any]) -> Any: """ if not isinstance(node, ast.AST): return node - if isinstance(node, ast.Index): # For compatibility + if sys.version_info < (3, 9) and isinstance(node, ast.Index): # For compatibility node = node.value - if isinstance(node, ast.Num): # For compatibility - return node.n if sys.version_info >= (3, 8): if isinstance(node, ast.Constant): return node.value + else: + if isinstance(node, ast.Num): # For compatibility + return node.n # Replace internal constants with their values node = copy_tree(node) @@ -112,7 +120,7 @@ def rname(node): if isinstance(node, str): return node - if isinstance(node, ast.Num): + if sys.version_info < (3, 8) and isinstance(node, ast.Num): return str(node.n) if isinstance(node, ast.Name): # form x return node.id @@ -174,12 +182,15 @@ def subscript_to_ast_slice(node, without_array=False): # Python <3.9 compatibility result_slice = None - if isinstance(node.slice, ast.Index): - slc = node.slice.value - if not isinstance(slc, ast.Tuple): - result_slice = [slc] - elif isinstance(node.slice, ast.ExtSlice): - slc = tuple(node.slice.dims) + if sys.version_info < (3, 9): + if isinstance(node.slice, ast.Index): + slc = node.slice.value + if not isinstance(slc, ast.Tuple): + result_slice = [slc] + elif isinstance(node.slice, ast.ExtSlice): + slc = tuple(node.slice.dims) + else: + raise TypeError('Unsupported slicing type: ' + str(type(node.slice))) else: slc = node.slice @@ -196,7 +207,7 @@ def subscript_to_ast_slice(node, without_array=False): # Slice if isinstance(s, ast.Slice): result_slice.append((s.lower, s.upper, s.step)) - elif isinstance(s, ast.Index): # Index (Python <3.9) + elif sys.version_info < (3, 9) and isinstance(s, ast.Index): # Index (Python <3.9) result_slice.append(s.value) else: # Index result_slice.append(s) @@ -226,7 +237,7 @@ def _Subscript(self, t): self.dispatch(t.value) self.write('[') # Compatibility - if isinstance(t.slice, ast.Index): + if sys.version_info < (3, 9) and isinstance(t.slice, ast.Index): slc = t.slice.value else: slc = t.slice @@ -600,7 +611,7 @@ def visit_Name(self, node: ast.Name): def visit_Constant(self, node): return self.visit_Num(node) - def visit_Num(self, node: ast.Num): + def visit_Num(self, node: NumConstant): newname = f'__uu{self.id}' self.gvars[newname] = node.n self.id += 1 From a8d7431d52fd936579faac1cf7636bb961436555 Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Sat, 7 Oct 2023 14:03:05 +0200 Subject: [PATCH 05/44] Reworked code to avoid deprecation warnings and errors. --- dace/frontend/python/newast.py | 53 +++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 17 deletions(-) diff --git a/dace/frontend/python/newast.py b/dace/frontend/python/newast.py index 71d834e955..3b0023c842 100644 --- a/dace/frontend/python/newast.py +++ b/dace/frontend/python/newast.py @@ -49,10 +49,29 @@ Shape = Union[ShapeTuple, ShapeList] DependencyType = Dict[str, Tuple[SDFGState, Union[Memlet, nodes.Tasklet], Tuple[int]]] + if sys.version_info < (3, 8): _simple_ast_nodes = (ast.Constant, ast.Name, ast.NameConstant, ast.Num) + BytesConstant = ast.Bytes + EllipsisConstant = ast.Ellipsis + NameConstant = ast.NameConstant + NumConstant = ast.Num + StrConstant = ast.Str else: _simple_ast_nodes = (ast.Constant, ast.Name) + BytesConstant = ast.Constant + EllipsisConstant = ast.Constant + NameConstant = ast.Constant + NumConstant = ast.Constant + StrConstant = ast.Constant + + +if sys.version_info < (3, 9): + Index = ast.Index + ExtSlice = ast.ExtSlice +else: + Index = type(None) + ExtSlice = type(None) class SkipCall(Exception): @@ -986,13 +1005,13 @@ def visit_TopLevelExpr(self, node): raise DaceSyntaxError(self, node, 'Local variable is already a tasklet input or output') self.outputs[connector] = memlet return None # Remove from final tasklet code - elif isinstance(node.value, ast.Str): + elif isinstance(node.value, StrConstant): return self.visit_TopLevelStr(node.value) return self.generic_visit(node) # Detect external tasklet code - def visit_TopLevelStr(self, node: ast.Str): + def visit_TopLevelStr(self, node: StrConstant): if self.extcode != None: raise DaceSyntaxError(self, node, 'Cannot provide more than one intrinsic implementation ' + 'for tasklet') self.extcode = node.s @@ -1616,7 +1635,7 @@ def _parse_for_indices(self, node: ast.Expr): return indices - def _parse_value(self, node: Union[ast.Name, ast.Num, ast.Constant]): + def _parse_value(self, node: Union[ast.Name, NumConstant, ast.Constant]): """Parses a value Arguments: @@ -1631,7 +1650,7 @@ def _parse_value(self, node: Union[ast.Name, ast.Num, ast.Constant]): if isinstance(node, ast.Name): return node.id - elif isinstance(node, ast.Num): + elif sys.version_info < (3.8) and isinstance(node, ast.Num): return str(node.n) elif isinstance(node, ast.Constant): return str(node.value) @@ -1651,14 +1670,14 @@ def _parse_slice(self, node: ast.Slice): return (self._parse_value(node.lower), self._parse_value(node.upper), self._parse_value(node.step) if node.step is not None else "1") - def _parse_index_as_range(self, node: Union[ast.Index, ast.Tuple]): + def _parse_index_as_range(self, node: Union[Index, ast.Tuple]): """ Parses an index as range :param node: Index node :return: Range in (from, to, step) format """ - if isinstance(node, ast.Index): + if sys.version_info < (3.9) and isinstance(node, ast.Index): val = self._parse_value(node.value) elif isinstance(node, ast.Tuple): val = self._parse_value(node.elts) @@ -1765,7 +1784,7 @@ def visit_ast_or_value(arg): iterator = 'dace.map' else: ranges = [] - if isinstance(node.slice, (ast.Tuple, ast.ExtSlice)): + if isinstance(node.slice, (ast.Tuple, ExtSlice)): for s in node.slice.dims: ranges.append(self._parse_slice(s)) elif isinstance(node.slice, ast.Slice): @@ -4297,7 +4316,7 @@ def visit_Call(self, node: ast.Call, create_callbacks=False): func = None funcname = None # If the call directly refers to an SDFG or dace-compatible program - if isinstance(node.func, ast.Num): + if sys.version_info < (3, 8) and isinstance(node.func, ast.Num): if self._has_sdfg(node.func.n): func = node.func.n elif isinstance(node.func, ast.Constant): @@ -4620,11 +4639,11 @@ def visit_Str(self, node: ast.Str): # A string constant returns a string literal return StringLiteral(node.s) - def visit_Bytes(self, node: ast.Bytes): + def visit_Bytes(self, node: BytesConstant): # A bytes constant returns a string literal return StringLiteral(node.s) - def visit_Num(self, node: ast.Num): + def visit_Num(self, node: NumConstant): if isinstance(node.n, bool): return dace.bool_(node.n) if isinstance(node.n, (int, float, complex)): @@ -4644,7 +4663,7 @@ def visit_Name(self, node: ast.Name): # If visiting a name, check if it is a defined variable or a global return self._visitname(node.id, node) - def visit_NameConstant(self, node: ast.NameConstant): + def visit_NameConstant(self, node: NameConstant): return self.visit_Constant(node) def visit_Attribute(self, node: ast.Attribute): @@ -4919,7 +4938,7 @@ def _promote(node: ast.AST) -> Union[Any, str, symbolic.symbol]: res = self.visit(s) else: res = self._visit_ast_or_value(s) - elif isinstance(s, ast.Index): + elif sys.version_info < (3.9) and isinstance(s, ast.Index): res = self._parse_subscript_slice(s.value) elif isinstance(s, ast.Slice): lower = s.lower @@ -4937,7 +4956,7 @@ def _promote(node: ast.AST) -> Union[Any, str, symbolic.symbol]: res = ((lower, upper, step), ) elif isinstance(s, ast.Tuple): res = tuple(self._parse_subscript_slice(d, multidim=True) for d in s.elts) - elif isinstance(s, ast.ExtSlice): + elif sys.version_info < (3, 9) and isinstance(s, ast.ExtSlice): res = tuple(self._parse_subscript_slice(d, multidim=True) for d in s.dims) else: res = _promote(s) @@ -4999,8 +5018,8 @@ def visit_Subscript(self, node: ast.Subscript, inference: bool = False): # If the value is a tuple of constants (e.g., array.shape) and the # slice is constant, return the value itself nslice = self.visit(node.slice) - if isinstance(nslice, (ast.Index, Number)): - if isinstance(nslice, ast.Index): + if isinstance(nslice, (Index, Number)): + if sys.version_info < (3, 9) and isinstance(nslice, ast.Index): v = self._parse_value(nslice.value) else: v = nslice @@ -5064,7 +5083,7 @@ def _visit_ast_or_value(self, node: ast.AST) -> Any: out = out[0] return out - def visit_Index(self, node: ast.Index) -> Any: + def visit_Index(self, node: Index) -> Any: if isinstance(node.value, ast.Tuple): for i, elt in enumerate(node.value.elts): node.value.elts[i] = self._visit_ast_or_value(elt) @@ -5072,7 +5091,7 @@ def visit_Index(self, node: ast.Index) -> Any: node.value = self._visit_ast_or_value(node.value) return node - def visit_ExtSlice(self, node: ast.ExtSlice) -> Any: + def visit_ExtSlice(self, node: ExtSlice) -> Any: for i, dim in enumerate(node.dims): node.dims[i] = self._visit_ast_or_value(dim) From 10108c7d0e723ba2786c8441fc5e7c42e9366b49 Mon Sep 17 00:00:00 2001 From: alexnick83 <31545860+alexnick83@users.noreply.github.com> Date: Sat, 7 Oct 2023 15:37:08 +0200 Subject: [PATCH 06/44] Fixed comma/dots. --- dace/frontend/python/newast.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dace/frontend/python/newast.py b/dace/frontend/python/newast.py index 3b0023c842..db4e716445 100644 --- a/dace/frontend/python/newast.py +++ b/dace/frontend/python/newast.py @@ -1650,7 +1650,7 @@ def _parse_value(self, node: Union[ast.Name, NumConstant, ast.Constant]): if isinstance(node, ast.Name): return node.id - elif sys.version_info < (3.8) and isinstance(node, ast.Num): + elif sys.version_info < (3, 8) and isinstance(node, ast.Num): return str(node.n) elif isinstance(node, ast.Constant): return str(node.value) @@ -1677,7 +1677,7 @@ def _parse_index_as_range(self, node: Union[Index, ast.Tuple]): :param node: Index node :return: Range in (from, to, step) format """ - if sys.version_info < (3.9) and isinstance(node, ast.Index): + if sys.version_info < (3, 9) and isinstance(node, ast.Index): val = self._parse_value(node.value) elif isinstance(node, ast.Tuple): val = self._parse_value(node.elts) From d8efaca067e471ddef3d65dae99a18ac3a26be1a Mon Sep 17 00:00:00 2001 From: alexnick83 <31545860+alexnick83@users.noreply.github.com> Date: Sat, 7 Oct 2023 16:26:58 +0200 Subject: [PATCH 07/44] Another comma/dot fix. --- dace/frontend/python/newast.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dace/frontend/python/newast.py b/dace/frontend/python/newast.py index db4e716445..1d0dbc34dd 100644 --- a/dace/frontend/python/newast.py +++ b/dace/frontend/python/newast.py @@ -4938,7 +4938,7 @@ def _promote(node: ast.AST) -> Union[Any, str, symbolic.symbol]: res = self.visit(s) else: res = self._visit_ast_or_value(s) - elif sys.version_info < (3.9) and isinstance(s, ast.Index): + elif sys.version_info < (3, 9) and isinstance(s, ast.Index): res = self._parse_subscript_slice(s.value) elif isinstance(s, ast.Slice): lower = s.lower From f4cb38aeca4c3a316312e7043cc82670b08d384c Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Sun, 8 Oct 2023 11:03:53 +0200 Subject: [PATCH 08/44] Reworked access to slice attribute. --- dace/frontend/python/astutils.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/dace/frontend/python/astutils.py b/dace/frontend/python/astutils.py index ff2d191752..49d7278462 100644 --- a/dace/frontend/python/astutils.py +++ b/dace/frontend/python/astutils.py @@ -182,15 +182,12 @@ def subscript_to_ast_slice(node, without_array=False): # Python <3.9 compatibility result_slice = None - if sys.version_info < (3, 9): - if isinstance(node.slice, ast.Index): - slc = node.slice.value - if not isinstance(slc, ast.Tuple): - result_slice = [slc] - elif isinstance(node.slice, ast.ExtSlice): - slc = tuple(node.slice.dims) - else: - raise TypeError('Unsupported slicing type: ' + str(type(node.slice))) + if sys.version_info < (3, 9) and isinstance(node.slice, ast.Index): + slc = node.slice.value + if not isinstance(slc, ast.Tuple): + result_slice = [slc] + elif sys.version_info < (3, 9) and isinstance(node.slice, ast.ExtSlice): + slc = tuple(node.slice.dims) else: slc = node.slice From 772a6299cd7301856a1f6f027f10a45d1b8183d4 Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Sun, 8 Oct 2023 11:56:47 +0200 Subject: [PATCH 09/44] Fixed invalid escape sequence backlash-space. --- dace/codegen/control_flow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dace/codegen/control_flow.py b/dace/codegen/control_flow.py index 28bf38f14d..a198ed371b 100644 --- a/dace/codegen/control_flow.py +++ b/dace/codegen/control_flow.py @@ -30,7 +30,7 @@ x < 5 /------>[s2]--------\\ - [s1] \ ->[s5] + [s1] \\ ->[s5] ------>[s3]->[s4]--/ x >= 5 From c9277cefc2f52a06adbbb02c4a9efd89eebf8d6b Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Sun, 8 Oct 2023 11:57:07 +0200 Subject: [PATCH 10/44] Using StrConstant instead of ast.Str. --- dace/frontend/python/newast.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dace/frontend/python/newast.py b/dace/frontend/python/newast.py index 1d0dbc34dd..eee6719825 100644 --- a/dace/frontend/python/newast.py +++ b/dace/frontend/python/newast.py @@ -4635,7 +4635,7 @@ def _visitname(self, name: str, node: ast.AST): return rname #### Visitors that return arrays - def visit_Str(self, node: ast.Str): + def visit_Str(self, node: StrConstant): # A string constant returns a string literal return StringLiteral(node.s) From 188480931d19954df770e663e5b684ae3f4ec822 Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Sun, 8 Oct 2023 12:00:46 +0200 Subject: [PATCH 11/44] Fixed invalid escape sequence backslash-asterisk. --- dace/codegen/instrumentation/papi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dace/codegen/instrumentation/papi.py b/dace/codegen/instrumentation/papi.py index bc7163ea9b..c0d3b657a1 100644 --- a/dace/codegen/instrumentation/papi.py +++ b/dace/codegen/instrumentation/papi.py @@ -448,7 +448,7 @@ class PAPIUtils(object): def available_counters() -> Dict[str, int]: """ Returns the available PAPI counters on this machine. Only works on - \*nix based systems with ``grep`` and ``papi-tools`` installed. + *nix based systems with ``grep`` and ``papi-tools`` installed. :return: A set of available PAPI counters in the form of a dictionary mapping from counter name to the number of native hardware From 209d44abfc2b556b9b132afbd576f11bd7bc7c55 Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Sun, 8 Oct 2023 12:02:30 +0200 Subject: [PATCH 12/44] Removed extraneous and deprecated alias. --- tests/fpga/hbm_transform_test.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/fpga/hbm_transform_test.py b/tests/fpga/hbm_transform_test.py index 6438ac7492..0346837fbc 100644 --- a/tests/fpga/hbm_transform_test.py +++ b/tests/fpga/hbm_transform_test.py @@ -1,7 +1,6 @@ -# Copyright 2019-2021 ETH Zurich and the DaCe authors. All rights reserved. +# Copyright 2019-2023 ETH Zurich and the DaCe authors. All rights reserved. from dace.fpga_testing import xilinx_test -from numpy.lib import math from dace.sdfg.state import SDFGState import numpy as np from dace import dtypes From b5cb4b6666143c4b8dc4e0b297e2a171c7cc752f Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Sun, 8 Oct 2023 12:09:53 +0200 Subject: [PATCH 13/44] Accesing numerical constant value with t.value for Python >= 3.8. --- dace/codegen/cppunparse.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/dace/codegen/cppunparse.py b/dace/codegen/cppunparse.py index 77dd34d478..2b1328ca8b 100644 --- a/dace/codegen/cppunparse.py +++ b/dace/codegen/cppunparse.py @@ -729,25 +729,26 @@ def _Repr(self, t): raise NotImplementedError('Invalid C++') def _Num(self, t): - repr_n = repr(t.n) + t_n = t.value if sys.version_info >= (3, 8) else t.n + repr_n = repr(t_n) # For complex values, use DTYPE_TO_TYPECLASS dictionary - if isinstance(t.n, complex): + if isinstance(t_n, complex): dtype = dtypes.DTYPE_TO_TYPECLASS[complex] # Handle large integer values - if isinstance(t.n, int): - bits = t.n.bit_length() + if isinstance(t_n, int): + bits = t_n.bit_length() if bits == 32: # Integer, potentially unsigned - if t.n >= 0: # unsigned + if t_n >= 0: # unsigned repr_n += 'U' else: # signed, 64-bit repr_n += 'LL' elif 32 < bits <= 63: repr_n += 'LL' - elif bits == 64 and t.n >= 0: + elif bits == 64 and t_n >= 0: repr_n += 'ULL' elif bits >= 64: - warnings.warn(f'Value wider than 64 bits encountered in expression ({t.n}), emitting as-is') + warnings.warn(f'Value wider than 64 bits encountered in expression ({t_n}), emitting as-is') if repr_n.endswith("j"): self.write("%s(0, %s)" % (dtype, repr_n.replace("inf", INFSTR)[:-1])) From 52011cbde9ebd427797ebbd456f9845fdc456b36 Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Sun, 8 Oct 2023 12:12:32 +0200 Subject: [PATCH 14/44] Accessing numerical constant value with node.value for Python >= 3.8. --- dace/frontend/python/astutils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dace/frontend/python/astutils.py b/dace/frontend/python/astutils.py index 49d7278462..67d8b6aded 100644 --- a/dace/frontend/python/astutils.py +++ b/dace/frontend/python/astutils.py @@ -610,7 +610,7 @@ def visit_Constant(self, node): def visit_Num(self, node: NumConstant): newname = f'__uu{self.id}' - self.gvars[newname] = node.n + self.gvars[newname] = node.value if sys.version_info >= (3, 8) else node.n self.id += 1 return ast.copy_location(ast.Name(id=newname, ctx=ast.Load()), node) From e4288ed4a07f0fa0b03aa81e04238275f9952b20 Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Sun, 8 Oct 2023 12:15:52 +0200 Subject: [PATCH 15/44] Accessing numerical constant value with node.func.value for Python >= 3.8. --- dace/frontend/python/preprocessing.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/dace/frontend/python/preprocessing.py b/dace/frontend/python/preprocessing.py index 239875118f..f65f4c4a01 100644 --- a/dace/frontend/python/preprocessing.py +++ b/dace/frontend/python/preprocessing.py @@ -20,6 +20,20 @@ from dace.frontend.python.common import (DaceSyntaxError, SDFGConvertible, SDFGClosure, StringLiteral) +if sys.version_info < (3, 8): + BytesConstant = ast.Bytes + EllipsisConstant = ast.Ellipsis + NameConstant = ast.NameConstant + NumConstant = ast.Num + StrConstant = ast.Str +else: + BytesConstant = ast.Constant + EllipsisConstant = ast.Constant + NameConstant = ast.Constant + NumConstant = ast.Constant + StrConstant = ast.Constant + + class DaceRecursionError(Exception): """ Exception that indicates a recursion in a data-centric parsed context. @@ -1358,7 +1372,7 @@ def _get_given_args(self, node: ast.Call, function: 'DaceProgram') -> Set[str]: def visit_Call(self, node: ast.Call): # Only parse calls to parsed SDFGConvertibles - if not isinstance(node.func, (ast.Num, ast.Constant)): + if not isinstance(node.func, (NumConstant, ast.Constant)): self.seen_calls.add(astutils.unparse(node.func)) return self.generic_visit(node) if hasattr(node.func, 'oldnode'): @@ -1366,10 +1380,7 @@ def visit_Call(self, node: ast.Call): self.seen_calls.add(astutils.unparse(node.func.oldnode.func)) else: self.seen_calls.add(astutils.rname(node.func.oldnode)) - if isinstance(node.func, ast.Num): - value = node.func.n - else: - value = node.func.value + value = node.func.value if sys.version_info >= (3, 8) else node.func.n if not hasattr(value, '__sdfg__') or isinstance(value, SDFG): return self.generic_visit(node) From 6afee58aedfedc5635e3607c328d6b7e56dfa77e Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Sun, 8 Oct 2023 12:19:51 +0200 Subject: [PATCH 16/44] ast.Ellipsis check predicated by Python < 3.8. --- dace/frontend/python/memlet_parser.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dace/frontend/python/memlet_parser.py b/dace/frontend/python/memlet_parser.py index aa9d4ddb0d..9bd051be5c 100644 --- a/dace/frontend/python/memlet_parser.py +++ b/dace/frontend/python/memlet_parser.py @@ -1,7 +1,7 @@ -# Copyright 2019-2021 ETH Zurich and the DaCe authors. All rights reserved. +# Copyright 2019-2023 ETH Zurich and the DaCe authors. All rights reserved. import ast import copy -import re +import sys from collections import namedtuple from typing import Any, Dict, List, Optional, Tuple, Union from dataclasses import dataclass @@ -114,7 +114,7 @@ def _fill_missing_slices(das, ast_ndslice, array, indices): offsets.append(idx) idx += 1 new_idx += 1 - elif (isinstance(dim, ast.Ellipsis) or dim is Ellipsis + elif ((sys.version_info < (3, 8) and isinstance(dim, ast.Ellipsis)) or dim is Ellipsis or (isinstance(dim, ast.Constant) and dim.value is Ellipsis) or (isinstance(dim, ast.Name) and dim.id is Ellipsis)): if has_ellipsis: From b302ec5157ac4107068210e33604c90d9b63fb50 Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Sun, 8 Oct 2023 12:20:49 +0200 Subject: [PATCH 17/44] Using NameConstant instead of ast.NameConstant. --- dace/frontend/python/memlet_parser.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/dace/frontend/python/memlet_parser.py b/dace/frontend/python/memlet_parser.py index 9bd051be5c..a95bf82046 100644 --- a/dace/frontend/python/memlet_parser.py +++ b/dace/frontend/python/memlet_parser.py @@ -16,6 +16,22 @@ MemletType = Union[ast.Call, ast.Attribute, ast.Subscript, ast.Name] +if sys.version_info < (3, 8): + _simple_ast_nodes = (ast.Constant, ast.Name, ast.NameConstant, ast.Num) + BytesConstant = ast.Bytes + EllipsisConstant = ast.Ellipsis + NameConstant = ast.NameConstant + NumConstant = ast.Num + StrConstant = ast.Str +else: + _simple_ast_nodes = (ast.Constant, ast.Name) + BytesConstant = ast.Constant + EllipsisConstant = ast.Constant + NameConstant = ast.Constant + NumConstant = ast.Constant + StrConstant = ast.Constant + + @dataclass class MemletExpr: name: str @@ -125,7 +141,7 @@ def _fill_missing_slices(das, ast_ndslice, array, indices): ndslice[j] = (0, array.shape[j] - 1, 1) idx += 1 new_idx += 1 - elif (dim is None or (isinstance(dim, (ast.Constant, ast.NameConstant)) and dim.value is None)): + elif (dim is None or (isinstance(dim, (ast.Constant, NameConstant)) and dim.value is None)): new_axes.append(new_idx) new_idx += 1 # NOTE: Do not increment idx here From fa1d5c78eba1b83dc043c59b1c26d74559de0513 Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Sun, 8 Oct 2023 12:23:34 +0200 Subject: [PATCH 18/44] Check for ast.Num predicated by Python < 3.8. --- dace/codegen/cppunparse.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dace/codegen/cppunparse.py b/dace/codegen/cppunparse.py index 2b1328ca8b..58d4b2cb66 100644 --- a/dace/codegen/cppunparse.py +++ b/dace/codegen/cppunparse.py @@ -985,7 +985,9 @@ def _Attribute(self, t): # Special case: 3.__abs__() is a syntax error, so if t.value # is an integer literal then we need to either parenthesize # it or add an extra space to get 3 .__abs__(). - if (isinstance(t.value, (ast.Num, ast.Constant)) and isinstance(t.value.n, int)): + if isinstance(t.value, ast.Constant) and isinstance(t.value.value, int): + self.write(" ") + elif sys.version_info < (3, 8) and isinstance(t.value, ast.Num) and isinstance(t.value.n, int): self.write(" ") if (isinstance(t.value, ast.Name) and t.value.id in ('dace', 'dace::math', 'dace::cmath')): self.write("::") From fa805f3f25b49aceb3b984f17bfd92f20eb8e379 Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Mon, 9 Oct 2023 09:10:31 +0200 Subject: [PATCH 19/44] Fixed invalid escape sequence backslash-space. --- dace/transformation/dataflow/mpi.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dace/transformation/dataflow/mpi.py b/dace/transformation/dataflow/mpi.py index 8138b86b26..b6a467dc21 100644 --- a/dace/transformation/dataflow/mpi.py +++ b/dace/transformation/dataflow/mpi.py @@ -23,9 +23,9 @@ class MPITransformMap(transformation.SingleStateTransformation): .. code-block:: text Input1 - Output1 - \ / + \\ / Input2 --- MapEntry -- Arbitrary R -- MapExit -- Output2 - / \ + / \\ InputN - OutputN From dbd286ddbb49121e3be0373cb113aa5d81c8f85c Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Mon, 9 Oct 2023 09:24:29 +0200 Subject: [PATCH 20/44] Predicated access to `n` attribute. --- dace/frontend/python/preprocessing.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dace/frontend/python/preprocessing.py b/dace/frontend/python/preprocessing.py index f65f4c4a01..052e823a2f 100644 --- a/dace/frontend/python/preprocessing.py +++ b/dace/frontend/python/preprocessing.py @@ -768,7 +768,8 @@ def visit_Subscript(self, node: ast.Subscript) -> Any: def visit_Call(self, node: ast.Call) -> Any: from dace.frontend.python.interface import in_program, inline # Avoid import loop - if hasattr(node.func, 'n') and isinstance(node.func.n, SDFGConvertible): + if (hasattr(node.func, 'value') and isinstance(node.func.value, SDFGConvertible) or + sys.version_info < (3, 8) and hasattr(node.func, 'n') and isinstance(node.func.n, SDFGConvertible)): # Skip already-parsed calls return self.generic_visit(node) From 1bfaee5807826709216285fb12e3561cd17b0ccc Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Mon, 9 Oct 2023 09:26:36 +0200 Subject: [PATCH 21/44] Fixed pytest None warning deprecation. --- tests/compile_sdfg_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compile_sdfg_test.py b/tests/compile_sdfg_test.py index 33ace1156a..3120359262 100644 --- a/tests/compile_sdfg_test.py +++ b/tests/compile_sdfg_test.py @@ -51,7 +51,7 @@ def tester(a: int): return a + 1 csdfg = tester.to_sdfg().compile() - with pytest.warns(None, match='Casting'): + with pytest.warns(UserWarning, match='Casting'): result = csdfg(0.1) assert result.item() == 1 From 8e0f88328cab1f0584382ccdff0131743e534fd0 Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Mon, 9 Oct 2023 09:32:19 +0200 Subject: [PATCH 22/44] Fixed pytest incorrect return deprecation warning. --- tests/blas/nodes/dot_test.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/blas/nodes/dot_test.py b/tests/blas/nodes/dot_test.py index d5f1d24263..e30f03785c 100755 --- a/tests/blas/nodes/dot_test.py +++ b/tests/blas/nodes/dot_test.py @@ -92,23 +92,23 @@ def run_test(target, size, vector_length): def test_dot_pure(): - return run_test("pure", 64, 1) + assert isinstance(run_test("pure", 64, 1), dace.SDFG) @xilinx_test() def test_dot_xilinx(): - return run_test("xilinx", 64, 16) + assert isinstance(run_test("xilinx", 64, 16), dace.SDFG) @xilinx_test() def test_dot_xilinx_decoupled(): with set_temporary("compiler", "xilinx", "decouple_array_interfaces", value=True): - return run_test("xilinx", 64, 16) + assert isinstance(run_test("xilinx", 64, 16), dace.SDFG) @intel_fpga_test() def test_dot_intel_fpga(): - return run_test("intel_fpga", 64, 16) + assert isinstance(run_test("intel_fpga", 64, 16), dace.SDFG) if __name__ == "__main__": @@ -119,4 +119,4 @@ def test_dot_intel_fpga(): args = parser.parse_args() size = args.N - run_test(target, size, vector_length) + run_test(args.target, size, args.vector_length) From b64f12486ad3b1ff7e908037e1c531d52b5118c1 Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Mon, 9 Oct 2023 09:33:42 +0200 Subject: [PATCH 23/44] Predicated access to s attribute. --- dace/frontend/python/newast.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dace/frontend/python/newast.py b/dace/frontend/python/newast.py index eee6719825..1d1294809c 100644 --- a/dace/frontend/python/newast.py +++ b/dace/frontend/python/newast.py @@ -1014,7 +1014,7 @@ def visit_TopLevelExpr(self, node): def visit_TopLevelStr(self, node: StrConstant): if self.extcode != None: raise DaceSyntaxError(self, node, 'Cannot provide more than one intrinsic implementation ' + 'for tasklet') - self.extcode = node.s + self.extcode = node.value if sys.version_info >= (3, 8) else node.s # TODO: Should get detected by _parse_Tasklet() if self.lang is None: From 70a61bb2590f8be414fa31992e357982e04a0ef7 Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Mon, 9 Oct 2023 09:35:33 +0200 Subject: [PATCH 24/44] Using NameConstant alias. --- dace/codegen/cppunparse.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/dace/codegen/cppunparse.py b/dace/codegen/cppunparse.py index 58d4b2cb66..d8d52846ac 100644 --- a/dace/codegen/cppunparse.py +++ b/dace/codegen/cppunparse.py @@ -87,6 +87,21 @@ from dace import dtypes from dace.codegen.tools import type_inference + +if sys.version_info < (3, 8): + BytesConstant = ast.Bytes + EllipsisConstant = ast.Ellipsis + NameConstant = ast.NameConstant + NumConstant = ast.Num + StrConstant = ast.Str +else: + BytesConstant = ast.Constant + EllipsisConstant = ast.Constant + NameConstant = ast.Constant + NumConstant = ast.Constant + StrConstant = ast.Constant + + # Large float and imaginary literals get turned into infinities in the AST. # We unparse those infinities to INFSTR. INFSTR = "1e" + repr(sys.float_info.max_10_exp + 1) @@ -574,7 +589,7 @@ def _generic_FunctionDef(self, t, is_async=False): self.write('/* async */ ') if getattr(t, "returns", False): - if isinstance(t.returns, ast.NameConstant): + if isinstance(t.returns, NameConstant): if t.returns.value is None: self.write('void') else: From f34cb508f1208c11868db4300732ccdd25812d79 Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Mon, 9 Oct 2023 09:37:51 +0200 Subject: [PATCH 25/44] Using NumConstant and predication for n atttribute access. --- dace/codegen/cppunparse.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dace/codegen/cppunparse.py b/dace/codegen/cppunparse.py index d8d52846ac..e4456e3e18 100644 --- a/dace/codegen/cppunparse.py +++ b/dace/codegen/cppunparse.py @@ -914,13 +914,13 @@ def _BinOp(self, t): self.write(")") # Special cases for powers elif t.op.__class__.__name__ == 'Pow': - if isinstance(t.right, (ast.Num, ast.Constant, ast.UnaryOp)): + if isinstance(t.right, (NumConstant, ast.Constant, ast.UnaryOp)): power = None - if isinstance(t.right, (ast.Num, ast.Constant)): - power = t.right.n + if isinstance(t.right, (NumConstant, ast.Constant)): + power = t.right.value if sys.version_info >= (3, 8) else t.right.n elif isinstance(t.right, ast.UnaryOp) and isinstance(t.right.op, ast.USub): - if isinstance(t.right.operand, (ast.Num, ast.Constant)): - power = -t.right.operand.n + if isinstance(t.right.operand, (NumConstant, ast.Constant)): + power = - (t.right.operand.value if sys.version_info >= (3, 8) else t.right.operand.n) if power is not None and int(power) == power: negative = power < 0 From 8689c63f3fa6b9d17913f841fbb2123e3876b87c Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Mon, 9 Oct 2023 09:40:49 +0200 Subject: [PATCH 26/44] Predicated access to n attribute. --- dace/codegen/targets/cpp.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dace/codegen/targets/cpp.py b/dace/codegen/targets/cpp.py index c3bf9c4027..960519e310 100644 --- a/dace/codegen/targets/cpp.py +++ b/dace/codegen/targets/cpp.py @@ -1,4 +1,4 @@ -# Copyright 2019-2021 ETH Zurich and the DaCe authors. All rights reserved. +# Copyright 2019-2023 ETH Zurich and the DaCe authors. All rights reserved. """ Helper functions for C++ code generation. NOTE: The C++ code generator is currently located in cpu.py. @@ -9,6 +9,7 @@ import itertools import math import numbers +import sys import warnings import sympy as sp @@ -1275,7 +1276,8 @@ def visit_BinOp(self, node: ast.BinOp): evaluated_constant = symbolic.evaluate(unparsed, self.constants) evaluated = symbolic.symstr(evaluated_constant, cpp_mode=True) value = ast.parse(evaluated).body[0].value - if isinstance(evaluated_node, numbers.Number) and evaluated_node != value.n: + if isinstance(evaluated_node, numbers.Number) and evaluated_node != ( + value.value if sys.info_version >= (3, 8) else value.n): raise TypeError node.right = ast.parse(evaluated).body[0].value except (TypeError, AttributeError, NameError, KeyError, ValueError, SyntaxError): From 2a756b95524075abbffde8012771f7214366a3a5 Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Mon, 9 Oct 2023 09:46:19 +0200 Subject: [PATCH 27/44] Fixed pytest mark misconfiguration. --- tests/library/gemm_test.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/library/gemm_test.py b/tests/library/gemm_test.py index df60d1aa43..07e9006ece 100644 --- a/tests/library/gemm_test.py +++ b/tests/library/gemm_test.py @@ -1,4 +1,4 @@ -# Copyright 2019-2021 ETH Zurich and the DaCe authors. All rights reserved. +# Copyright 2019-2023 ETH Zurich and the DaCe authors. All rights reserved. import pytest import warnings import itertools @@ -132,7 +132,10 @@ def numpy_gemm(A, B, C, transA, transB, alpha, beta): assert diff <= 1e-5 -@pytest.mark.parametrize(('implementation', ), [('pure', ), ('MKL', ), pytest.param('cuBLAS', marks=pytest.mark.gpu)]) +@pytest.mark.parametrize( + ('implementation', ), + [('pure', ), pytest.param('MKL', marks=pytest.mark.mkl), + pytest.param('cuBLAS', marks=pytest.mark.gpu)]) def test_library_gemm(implementation): param_grid_trans = dict( transA=[True, False], From 736bd0b4c78e02ea58fdc35cfc9ae058c91cc450 Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Mon, 9 Oct 2023 09:49:27 +0200 Subject: [PATCH 28/44] Using Index and NumConstant. --- dace/libraries/stencil/subscript_converter.py | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/dace/libraries/stencil/subscript_converter.py b/dace/libraries/stencil/subscript_converter.py index 8abb3fc6c8..d159b345cb 100644 --- a/dace/libraries/stencil/subscript_converter.py +++ b/dace/libraries/stencil/subscript_converter.py @@ -1,9 +1,34 @@ -# Copyright 2019-2021 ETH Zurich and the DaCe authors. All rights reserved. +# Copyright 2019-2023 ETH Zurich and the DaCe authors. All rights reserved. import ast +import sys from collections import defaultdict from typing import Tuple +if sys.version_info < (3, 8): + _simple_ast_nodes = (ast.Constant, ast.Name, ast.NameConstant, ast.Num) + BytesConstant = ast.Bytes + EllipsisConstant = ast.Ellipsis + NameConstant = ast.NameConstant + NumConstant = ast.Num + StrConstant = ast.Str +else: + _simple_ast_nodes = (ast.Constant, ast.Name) + BytesConstant = ast.Constant + EllipsisConstant = ast.Constant + NameConstant = ast.Constant + NumConstant = ast.Constant + StrConstant = ast.Constant + + +if sys.version_info < (3, 9): + Index = ast.Index + ExtSlice = ast.ExtSlice +else: + Index = type(None) + ExtSlice = type(None) + + class SubscriptConverter(ast.NodeTransformer): """ Finds all subscript accesses using constant indices in the given code, and @@ -67,9 +92,9 @@ def visit_Subscript(self, node: ast.Subscript): # This can be a bunch of different things, varying between Python 3.8 # and Python 3.9, so try hard to unpack it into an index we can use. index_tuple = node.slice - if isinstance(index_tuple, (ast.Subscript, ast.Index)): + if isinstance(index_tuple, (ast.Subscript, Index)): index_tuple = index_tuple.value - if isinstance(index_tuple, (ast.Constant, ast.Num)): + if isinstance(index_tuple, (ast.Constant, NumConstant)): index_tuple = (index_tuple, ) if isinstance(index_tuple, ast.Tuple): index_tuple = index_tuple.elts From e553510c476c1eee822e31a8fe97c52b5f4dec8f Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Mon, 9 Oct 2023 09:55:33 +0200 Subject: [PATCH 29/44] Refactored if chain/nest --- dace/frontend/python/preprocessing.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dace/frontend/python/preprocessing.py b/dace/frontend/python/preprocessing.py index 052e823a2f..3f06b81f63 100644 --- a/dace/frontend/python/preprocessing.py +++ b/dace/frontend/python/preprocessing.py @@ -356,13 +356,13 @@ def remake_dict(args): # Remake keyword argument names from AST kwarg_names = [] for kw in arg.keys: - if isinstance(kw, ast.Num): + if sys.version_info >= (3, 8) and isinstance(kw, ast.Constant): + kwarg_names.append(kw.value) + elif sys.version_info < (3, 8) and isinstance(kw, ast.Num): kwarg_names.append(kw.n) - elif isinstance(kw, (ast.Str, ast.Bytes)): + elif sys.version_info < (3, 8) and isinstance(kw, (ast.Str, ast.Bytes)): kwarg_names.append(kw.s) - elif isinstance(kw, ast.NameConstant): - kwarg_names.append(kw.value) - elif sys.version_info >= (3, 8) and isinstance(kw, ast.Constant): + elif sys.version_info < (3, 8) and isinstance(kw, ast.NameConstant): kwarg_names.append(kw.value) else: raise NotImplementedError(f'Key type {type(kw).__name__} is not supported') From 5ae0b4731826faa38847cd084d3c8e9a9cd0eccb Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Mon, 9 Oct 2023 10:00:52 +0200 Subject: [PATCH 30/44] Fixed use of ast.Str. --- dace/frontend/python/preprocessing.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dace/frontend/python/preprocessing.py b/dace/frontend/python/preprocessing.py index 3f06b81f63..c2d8cebd10 100644 --- a/dace/frontend/python/preprocessing.py +++ b/dace/frontend/python/preprocessing.py @@ -873,7 +873,8 @@ def visit_JoinedStr(self, node: ast.JoinedStr) -> Any: parsed = [ not isinstance(v, ast.FormattedValue) or isinstance(v.value, ast.Constant) for v in visited.values ] - values = [v.s if isinstance(v, ast.Str) else astutils.unparse(v.value) for v in visited.values] + # NOTE: In Python < 3.8, v should be ast.Str. In Python 3.8 and later, it is (probably) ast.Constant. + values = [astutils.unparse(v.value) if sys.vesion_info >= (3, 8) else v.s for v in visited.values] return ast.copy_location( ast.Constant(kind='', value=''.join(('{%s}' % v) if not p else v for p, v in zip(parsed, values))), node) From fead1d6b60b95c14966216081b764cef7eb742b1 Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Mon, 9 Oct 2023 10:05:00 +0200 Subject: [PATCH 31/44] Fixed ast.Num and n attribute. --- dace/codegen/tools/type_inference.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/dace/codegen/tools/type_inference.py b/dace/codegen/tools/type_inference.py index 8ee8632c65..f159088461 100644 --- a/dace/codegen/tools/type_inference.py +++ b/dace/codegen/tools/type_inference.py @@ -338,7 +338,15 @@ def _BinOp(t, symbols, inferred_symbols): return dtypes.result_type_of(type_left, type_right) # Special case for integer power elif t.op.__class__.__name__ == 'Pow': - if (isinstance(t.right, (ast.Num, ast.Constant)) and int(t.right.n) == t.right.n and t.right.n >= 0): + if (sys.version_info >= (3, 8) and isinstance(t.right, ast.Constant) and + int(t.right.value) == t.right.value and t.right.value >= 0): + if t.right.value != 0: + type_left = _dispatch(t.left, symbols, inferred_symbols) + for i in range(int(t.right.n) - 1): + _dispatch(t.left, symbols, inferred_symbols) + return dtypes.result_type_of(type_left, dtypes.typeclass(np.uint32)) + elif (sys.version_info < (3, 8) and isinstance(t.right, ast.Num) and + int(t.right.n) == t.right.n and t.right.n >= 0): if t.right.n != 0: type_left = _dispatch(t.left, symbols, inferred_symbols) for i in range(int(t.right.n) - 1): From e5c6451dd4dce2cd84c2ca0301e91ba3bf9c277c Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Mon, 9 Oct 2023 10:30:22 +0200 Subject: [PATCH 32/44] Disallowing type aliases. --- dace/frontend/python/newast.py | 5 ++++- tests/python_frontend/type_statement_test.py | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 tests/python_frontend/type_statement_test.py diff --git a/dace/frontend/python/newast.py b/dace/frontend/python/newast.py index 1d1294809c..e6f9247157 100644 --- a/dace/frontend/python/newast.py +++ b/dace/frontend/python/newast.py @@ -303,7 +303,7 @@ def repl_callback(repldict): # Extra AST node types that are disallowed after preprocessing _DISALLOWED_STMTS = DISALLOWED_STMTS + [ 'Global', 'Assert', 'Print', 'Nonlocal', 'Raise', 'Starred', 'AsyncFor', 'ListComp', 'GeneratorExp', 'SetComp', - 'DictComp', 'comprehension' + 'DictComp', 'comprehension', 'TypeAlias' ] TaskletType = Union[ast.FunctionDef, ast.With, ast.For] @@ -4712,6 +4712,9 @@ def visit_Dict(self, node: ast.Dict): def visit_Lambda(self, node: ast.Lambda): # Return a string representation of the function return astutils.unparse(node) + + def visit_TypeAlias(self, node: ast.TypeAlias): + raise NotImplementedError('Type aliases are not supported in DaCe') ############################################################ diff --git a/tests/python_frontend/type_statement_test.py b/tests/python_frontend/type_statement_test.py new file mode 100644 index 0000000000..bdd168a158 --- /dev/null +++ b/tests/python_frontend/type_statement_test.py @@ -0,0 +1,19 @@ +# Copyright 2019-2023 ETH Zurich and the DaCe authors. All rights reserved. +import dace +import pytest + + +def test_type_statement(): + + @dace.program + def type_statement(): + type Scalar[T] = T + A: Scalar[dace.float32] = 0 + return A + + with pytest.raises(dace.frontend.python.common.DaceSyntaxError): + type_statement() + + +if __name__ == '__main__': + test_type_statement() From 9a96ef3606e80c049a3678af154744d013b44d8e Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Mon, 9 Oct 2023 11:06:38 +0200 Subject: [PATCH 33/44] Fixed TypeAlias for older Python versions. --- dace/frontend/python/newast.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/dace/frontend/python/newast.py b/dace/frontend/python/newast.py index e6f9247157..7831b4d81a 100644 --- a/dace/frontend/python/newast.py +++ b/dace/frontend/python/newast.py @@ -74,6 +74,12 @@ ExtSlice = type(None) +if sys.version_info < (3, 12): + TypeAlias = type(None) +else: + TypeAlias = ast.TypeAlias + + class SkipCall(Exception): """ Exception used to skip calls to functions that cannot be parsed. """ pass @@ -4713,7 +4719,7 @@ def visit_Lambda(self, node: ast.Lambda): # Return a string representation of the function return astutils.unparse(node) - def visit_TypeAlias(self, node: ast.TypeAlias): + def visit_TypeAlias(self, node: TypeAlias): raise NotImplementedError('Type aliases are not supported in DaCe') ############################################################ From e8317ed137376c11999d8d30567ff1fb1b2ef1b4 Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Mon, 9 Oct 2023 11:14:03 +0200 Subject: [PATCH 34/44] Don't run test for Python < 3.12. --- tests/python_frontend/type_statement_test.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/python_frontend/type_statement_test.py b/tests/python_frontend/type_statement_test.py index bdd168a158..1b8a27c72e 100644 --- a/tests/python_frontend/type_statement_test.py +++ b/tests/python_frontend/type_statement_test.py @@ -1,6 +1,7 @@ # Copyright 2019-2023 ETH Zurich and the DaCe authors. All rights reserved. import dace import pytest +import sys def test_type_statement(): @@ -11,8 +12,11 @@ def type_statement(): A: Scalar[dace.float32] = 0 return A - with pytest.raises(dace.frontend.python.common.DaceSyntaxError): - type_statement() + if sys.version_info >= (3, 12): + with pytest.raises(dace.frontend.python.common.DaceSyntaxError): + type_statement() + else: + assert True if __name__ == '__main__': From d1d461649e062edeac98bef827493e5c6a2af9da Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Mon, 9 Oct 2023 11:54:02 +0200 Subject: [PATCH 35/44] Fixed typo. --- dace/frontend/python/preprocessing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dace/frontend/python/preprocessing.py b/dace/frontend/python/preprocessing.py index c2d8cebd10..3786c4caea 100644 --- a/dace/frontend/python/preprocessing.py +++ b/dace/frontend/python/preprocessing.py @@ -874,7 +874,7 @@ def visit_JoinedStr(self, node: ast.JoinedStr) -> Any: not isinstance(v, ast.FormattedValue) or isinstance(v.value, ast.Constant) for v in visited.values ] # NOTE: In Python < 3.8, v should be ast.Str. In Python 3.8 and later, it is (probably) ast.Constant. - values = [astutils.unparse(v.value) if sys.vesion_info >= (3, 8) else v.s for v in visited.values] + values = [astutils.unparse(v.value) if sys.version_info >= (3, 8) else v.s for v in visited.values] return ast.copy_location( ast.Constant(kind='', value=''.join(('{%s}' % v) if not p else v for p, v in zip(parsed, values))), node) From b41ba7e236fdc80b3ffd800e483cf1c6f278a16d Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Mon, 9 Oct 2023 12:10:22 +0200 Subject: [PATCH 36/44] Fixed typo. --- dace/codegen/targets/cpp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dace/codegen/targets/cpp.py b/dace/codegen/targets/cpp.py index 960519e310..3d26f76214 100644 --- a/dace/codegen/targets/cpp.py +++ b/dace/codegen/targets/cpp.py @@ -1277,7 +1277,7 @@ def visit_BinOp(self, node: ast.BinOp): evaluated = symbolic.symstr(evaluated_constant, cpp_mode=True) value = ast.parse(evaluated).body[0].value if isinstance(evaluated_node, numbers.Number) and evaluated_node != ( - value.value if sys.info_version >= (3, 8) else value.n): + value.value if sys.version_info >= (3, 8) else value.n): raise TypeError node.right = ast.parse(evaluated).body[0].value except (TypeError, AttributeError, NameError, KeyError, ValueError, SyntaxError): From 52002ac1a67235b85856462ec4853d35e20287c2 Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Mon, 9 Oct 2023 12:13:58 +0200 Subject: [PATCH 37/44] Trying to disable test for Python < 3.12. --- tests/python_frontend/type_statement_test.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/tests/python_frontend/type_statement_test.py b/tests/python_frontend/type_statement_test.py index 1b8a27c72e..bf53ca5150 100644 --- a/tests/python_frontend/type_statement_test.py +++ b/tests/python_frontend/type_statement_test.py @@ -6,16 +6,19 @@ def test_type_statement(): - @dace.program - def type_statement(): - type Scalar[T] = T - A: Scalar[dace.float32] = 0 - return A - if sys.version_info >= (3, 12): + + @dace.program + def type_statement(): + type Scalar[T] = T + A: Scalar[dace.float32] = 0 + return A + with pytest.raises(dace.frontend.python.common.DaceSyntaxError): type_statement() + else: + assert True From 6c90205424cbe4d72d4ff7e48c923fb52564bfce Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Mon, 9 Oct 2023 12:19:07 +0200 Subject: [PATCH 38/44] Added py312 mark. --- pytest.ini | 1 + tests/python_frontend/type_statement_test.py | 22 +++++++------------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/pytest.ini b/pytest.ini index 087be3d897..513158f531 100644 --- a/pytest.ini +++ b/pytest.ini @@ -14,6 +14,7 @@ markers = scalapack: Test requires ScaLAPACK (Intel MKL and OpenMPI). (select with '-m scalapack') datainstrument: Test uses data instrumentation (select with '-m datainstrument') hptt: Test requires the HPTT library (select with '-m "hptt') + py312: Test requires Python 3.12 or later (select with '-m "py312"') python_files = *_test.py *_cudatest.py diff --git a/tests/python_frontend/type_statement_test.py b/tests/python_frontend/type_statement_test.py index bf53ca5150..2009529f3a 100644 --- a/tests/python_frontend/type_statement_test.py +++ b/tests/python_frontend/type_statement_test.py @@ -1,25 +1,19 @@ # Copyright 2019-2023 ETH Zurich and the DaCe authors. All rights reserved. import dace import pytest -import sys +@pytest.mark.py312 def test_type_statement(): - if sys.version_info >= (3, 12): - - @dace.program - def type_statement(): - type Scalar[T] = T - A: Scalar[dace.float32] = 0 - return A - - with pytest.raises(dace.frontend.python.common.DaceSyntaxError): - type_statement() + @dace.program + def type_statement(): + type Scalar[T] = T + A: Scalar[dace.float32] = 0 + return A - else: - - assert True + with pytest.raises(dace.frontend.python.common.DaceSyntaxError): + type_statement() if __name__ == '__main__': From a9cc68652f77a795505519a4351f2f71b2d5c858 Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Mon, 9 Oct 2023 12:23:54 +0200 Subject: [PATCH 39/44] Comment out test. --- tests/python_frontend/type_statement_test.py | 22 +++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/tests/python_frontend/type_statement_test.py b/tests/python_frontend/type_statement_test.py index 2009529f3a..16ec1613db 100644 --- a/tests/python_frontend/type_statement_test.py +++ b/tests/python_frontend/type_statement_test.py @@ -3,18 +3,20 @@ import pytest -@pytest.mark.py312 -def test_type_statement(): +# TODO: Investigate why pytest parses the DaCeProgram, even when the test is not supposed to run. +# @pytest.mark.py312 +# def test_type_statement(): - @dace.program - def type_statement(): - type Scalar[T] = T - A: Scalar[dace.float32] = 0 - return A +# @dace.program +# def type_statement(): +# type Scalar[T] = T +# A: Scalar[dace.float32] = 0 +# return A - with pytest.raises(dace.frontend.python.common.DaceSyntaxError): - type_statement() +# with pytest.raises(dace.frontend.python.common.DaceSyntaxError): +# type_statement() if __name__ == '__main__': - test_type_statement() + # test_type_statement() + pass From d5e656ea79c38ba48fe535f5ad5e9925da70f964 Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Mon, 9 Oct 2023 16:10:27 +0200 Subject: [PATCH 40/44] Fixed JoinedStr visitor method. --- dace/frontend/python/preprocessing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dace/frontend/python/preprocessing.py b/dace/frontend/python/preprocessing.py index 3786c4caea..af02d6f7d9 100644 --- a/dace/frontend/python/preprocessing.py +++ b/dace/frontend/python/preprocessing.py @@ -874,7 +874,7 @@ def visit_JoinedStr(self, node: ast.JoinedStr) -> Any: not isinstance(v, ast.FormattedValue) or isinstance(v.value, ast.Constant) for v in visited.values ] # NOTE: In Python < 3.8, v should be ast.Str. In Python 3.8 and later, it is (probably) ast.Constant. - values = [astutils.unparse(v.value) if sys.version_info >= (3, 8) else v.s for v in visited.values] + values = [v.s if sys.version_info < (3, 8) and isinstance(v, ast.Str) else v.value for v in visited.values] return ast.copy_location( ast.Constant(kind='', value=''.join(('{%s}' % v) if not p else v for p, v in zip(parsed, values))), node) From 650e386f55279eeb48c93c35fe72bd036960d8cd Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Mon, 9 Oct 2023 16:21:36 +0200 Subject: [PATCH 41/44] Added more disallowed statements. --- dace/frontend/python/newast.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dace/frontend/python/newast.py b/dace/frontend/python/newast.py index 7831b4d81a..733c3c7f62 100644 --- a/dace/frontend/python/newast.py +++ b/dace/frontend/python/newast.py @@ -309,7 +309,7 @@ def repl_callback(repldict): # Extra AST node types that are disallowed after preprocessing _DISALLOWED_STMTS = DISALLOWED_STMTS + [ 'Global', 'Assert', 'Print', 'Nonlocal', 'Raise', 'Starred', 'AsyncFor', 'ListComp', 'GeneratorExp', 'SetComp', - 'DictComp', 'comprehension', 'TypeAlias' + 'DictComp', 'comprehension', 'TypeAlias', 'TypeVar', 'ParamSpec', 'TypeVarTuple' ] TaskletType = Union[ast.FunctionDef, ast.With, ast.For] From 4cf69590084cb2010cb66d3bd080a0c1162f0892 Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Mon, 9 Oct 2023 18:08:29 +0200 Subject: [PATCH 42/44] Unparsing constant. --- dace/frontend/python/preprocessing.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dace/frontend/python/preprocessing.py b/dace/frontend/python/preprocessing.py index af02d6f7d9..1636e57ad0 100644 --- a/dace/frontend/python/preprocessing.py +++ b/dace/frontend/python/preprocessing.py @@ -873,8 +873,8 @@ def visit_JoinedStr(self, node: ast.JoinedStr) -> Any: parsed = [ not isinstance(v, ast.FormattedValue) or isinstance(v.value, ast.Constant) for v in visited.values ] - # NOTE: In Python < 3.8, v should be ast.Str. In Python 3.8 and later, it is (probably) ast.Constant. - values = [v.s if sys.version_info < (3, 8) and isinstance(v, ast.Str) else v.value for v in visited.values] + values = [v.s if sys.version_info < (3, 8) and isinstance(v, ast.Str) else astutils.unparse(v.value) + for v in visited.values] return ast.copy_location( ast.Constant(kind='', value=''.join(('{%s}' % v) if not p else v for p, v in zip(parsed, values))), node) From d79a4039c893a5ecb4d706b410b7314da8044189 Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Mon, 9 Oct 2023 19:27:14 +0200 Subject: [PATCH 43/44] Revered changes to FPGA tests. --- tests/blas/nodes/dot_test.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/blas/nodes/dot_test.py b/tests/blas/nodes/dot_test.py index e30f03785c..a936be60a9 100755 --- a/tests/blas/nodes/dot_test.py +++ b/tests/blas/nodes/dot_test.py @@ -95,20 +95,23 @@ def test_dot_pure(): assert isinstance(run_test("pure", 64, 1), dace.SDFG) +# TODO: Refactor to use assert or return True/False (pytest deprecation of returning non-booleans) @xilinx_test() def test_dot_xilinx(): - assert isinstance(run_test("xilinx", 64, 16), dace.SDFG) + return run_test("xilinx", 64, 16) +# TODO: Refactor to use assert or return True/False (pytest deprecation of returning non-booleans) @xilinx_test() def test_dot_xilinx_decoupled(): with set_temporary("compiler", "xilinx", "decouple_array_interfaces", value=True): - assert isinstance(run_test("xilinx", 64, 16), dace.SDFG) + return run_test("xilinx", 64, 16) +# TODO: Refactor to use assert or return True/False (pytest deprecation of returning non-booleans) @intel_fpga_test() def test_dot_intel_fpga(): - assert isinstance(run_test("intel_fpga", 64, 16), dace.SDFG) + return run_test("intel_fpga", 64, 16) if __name__ == "__main__": From 159033e817f86bb3f35b14dca10fcfc71e798b02 Mon Sep 17 00:00:00 2001 From: Alexandros Nikolaos Ziogas Date: Mon, 9 Oct 2023 21:24:45 +0200 Subject: [PATCH 44/44] Removed py312 mark. --- pytest.ini | 1 - 1 file changed, 1 deletion(-) diff --git a/pytest.ini b/pytest.ini index 513158f531..087be3d897 100644 --- a/pytest.ini +++ b/pytest.ini @@ -14,7 +14,6 @@ markers = scalapack: Test requires ScaLAPACK (Intel MKL and OpenMPI). (select with '-m scalapack') datainstrument: Test uses data instrumentation (select with '-m datainstrument') hptt: Test requires the HPTT library (select with '-m "hptt') - py312: Test requires Python 3.12 or later (select with '-m "py312"') python_files = *_test.py *_cudatest.py