From e356d8a5892939ad3a3b39c3355120d31229ab07 Mon Sep 17 00:00:00 2001 From: Josy Boelen Date: Mon, 3 Jun 2024 11:57:39 +0200 Subject: [PATCH] Removed support for Python 3.7 (which is End Of Life since 2023-06-27) (#430) * Removed support for Python 3.7 (which is End Of Life since 2023-06-27) Removed stray ast.Str and the like , which throw deprecation warnings in Python 3.12 * corrected import pathj for raises_kind * corrected `ord` value assignemnt in _toVerilog.py removed forgotten ast.dump call from _analyze.py --- .github/workflows/test_checkin.yml | 4 +- myhdl/__init__.py | 2 +- myhdl/conversion/_analyze.py | 74 ++---- myhdl/conversion/_toVHDL.py | 225 +++++------------- myhdl/conversion/_toVerilog.py | 95 ++------ .../conversion/general/test_ShadowSignal.py | 1 + setup.py | 5 +- 7 files changed, 122 insertions(+), 284 deletions(-) diff --git a/.github/workflows/test_checkin.yml b/.github/workflows/test_checkin.yml index 834bb9d8..1ade964e 100644 --- a/.github/workflows/test_checkin.yml +++ b/.github/workflows/test_checkin.yml @@ -34,7 +34,7 @@ jobs: strategy: fail-fast: false # So that one fail doesn't stop remaining tests matrix: - python-version: ["3.7", "3.8", "3.9", "3.10", "pypy-3.9", "3.11"] + python-version: ["3.8", "3.9", "pypy-3.9", "3.10", "pypy-3.10","3.11", "3.12"] target: [core, iverilog, ghdl] runs-on: ubuntu-latest needs: [run_lint, build_ghdl_linux, build_iverilog_linux] @@ -85,7 +85,7 @@ jobs: strategy: fail-fast: false # So that one fail doesn't stop remaining tests matrix: - python-version: ["3.11"] + python-version: ["3.12"] #target: [core, iverilog, ghdl] target: [core, ghdl] runs-on: windows-latest diff --git a/myhdl/__init__.py b/myhdl/__init__.py index adc765c6..95b89039 100644 --- a/myhdl/__init__.py +++ b/myhdl/__init__.py @@ -49,7 +49,7 @@ traceSignals -- function that enables signal tracing in a VCD file toVerilog -- function that converts a design to Verilog """ -__version__ = "0.11.45" +__version__ = "0.11.46" class StopSimulation(Exception): diff --git a/myhdl/conversion/_analyze.py b/myhdl/conversion/_analyze.py index 4c5f4d23..d8507989 100644 --- a/myhdl/conversion/_analyze.py +++ b/myhdl/conversion/_analyze.py @@ -30,7 +30,6 @@ import ast import builtins from itertools import chain -import myhdl import myhdl from myhdl import * from myhdl import ConversionError @@ -268,12 +267,8 @@ class _FirstPassVisitor(ast.NodeVisitor, _ConversionMixin): def visit_Call(self, node): # ast.Call signature changed in python 3.5 # http://greentreesnakes.readthedocs.org/en/latest/nodes.html#Call - if sys.version_info >= (3, 5): - starargs = any(isinstance(arg, ast.Starred) for arg in node.args) - kwargs = any(kw.arg is None for kw in node.keywords) - else: - starargs = node.starargs is not None - kwargs = node.kwargs is not None + starargs = any(isinstance(arg, ast.Starred) for arg in node.args) + kwargs = any(kw.arg is None for kw in node.keywords) if starargs: self.raiseError(node, _error.NotSupported, "extra positional arguments") @@ -297,8 +292,8 @@ class _FirstPassVisitor(ast.NodeVisitor, _ConversionMixin): # put official docstrings aside for separate processing node.doc = None if node.body and isinstance(node.body[0], ast.Expr) and \ - isinstance(node.body[0].value, ast.Str): - node.doc = node.body[0].value.s + isinstance(node.body[0].value, ast.Constant) and isinstance(node.body[0].value.value, str): + node.doc = node.body[0].value.value node.body = node.body[1:] self.visitList(node.body) @@ -594,7 +589,11 @@ class _AnalyzeVisitor(ast.NodeVisitor, _ConversionMixin): # # node.obj = _EdgeDetector() elif f is ord: node.obj = int(-1) - if not (isinstance(node.args[0], ast.Str) and (len(node.args[0].s) == 1)): + if isinstance(node.args[0], ast.Constant) and \ + isinstance(node.args[0].value, str) and \ + (len(node.args[0].value) == 1): + pass + else: self.raiseError(node, _error.NotSupported, "ord: expect string argument with length 1") elif f is delay: @@ -682,41 +681,20 @@ class _AnalyzeVisitor(ast.NodeVisitor, _ConversionMixin): elif v == 1: node.edge = sig.posedge - if sys.version_info >= (3, 9, 0): - - def visit_Constant(self, node): - node.obj = None # safeguarding? - # ToDo check for tuples? - if isinstance(node.value, int): - # Num - if node.value in (0, 1): - node.obj = bool(node.value) - else: - node.obj = node.value - elif node.value in (True, False, None): - # NameConstant - node.obj = node.value - elif isinstance(node.value, str): - # Str - node.obj = node.value - - else: - - def visit_Num(self, node): - n = node.n - # assign to value attribute for backwards compatibility - node.value = n - if n in (0, 1): - node.obj = bool(n) - elif isinstance(n, int): - node.obj = n + def visit_Constant(self, node): + node.obj = None # safeguarding? + # ToDo check for tuples? + if isinstance(node.value, int): + # Num + if node.value in (0, 1): + node.obj = bool(node.value) else: - node.obj = None - - def visit_Str(self, node): - node.obj = node.s - - def visit_NameConstant(self, node): + node.obj = node.value + elif node.value in (True, False, None): + # NameConstant + node.obj = node.value + elif isinstance(node.value, str): + # Str node.obj = node.value def visit_Continue(self, node): @@ -918,12 +896,12 @@ class _AnalyzeVisitor(ast.NodeVisitor, _ConversionMixin): for n in node.args: if isinstance(n, ast.BinOp) and isinstance(n.op, ast.Mod) and \ - isinstance(n.left, ast.Str): + isinstance(n.left, ast.Constant) and isinstance(n.left.value, str): if isinstance(n.right, ast.Tuple): a.extend(n.right.elts) else: a.append(n.right) - s = n.left.s + s = n.left.value while s: if not s: break @@ -950,8 +928,8 @@ class _AnalyzeVisitor(ast.NodeVisitor, _ConversionMixin): s = s[m.end():] continue self.raiseError(node, _error.UnsupportedFormatString, "%s" % s) - elif isinstance(n, ast.Str): - f.append(n.s) + elif isinstance(n, ast.Constant) and isinstance(n.value, str): + f.append(n.value) else: f.append(defaultConvSpec) a.append(n) diff --git a/myhdl/conversion/_toVHDL.py b/myhdl/conversion/_toVHDL.py index b9820730..22e32b00 100644 --- a/myhdl/conversion/_toVHDL.py +++ b/myhdl/conversion/_toVHDL.py @@ -937,64 +937,35 @@ class _ConvertVisitor(ast.NodeVisitor, _ConversionMixin): # in python3 a negative Num is represented as an USub of a positive Num # Fix: restore python2 behavior by a shortcut: invert value of Constant, inherit # vhdl type from UnaryOp node, and visit the modified operand - if sys.version_info >= (3, 8, 0): - if isinstance(node.op, ast.USub) and isinstance(node.operand, ast.Constant): - node.operand.n = -node.operand.n - node.operand.vhd = node.vhd - self.visit(node.operand) - return + if isinstance(node.op, ast.USub) and isinstance(node.operand, ast.Constant) and isinstance(node.operand.value, int): + # assume number + node.operand.value = -node.operand.value + node.operand.vhd = node.vhd + self.visit(node.operand) + return - pre, suf = self.inferCast(node.vhd, node.vhdOri) - if isinstance(node.op, ast.UAdd): - op = "" - else: - op = opmap[type(node.op)] - - if isinstance(node.operand, ast.Constant): - self.write("(") - self.write(op) - self.write("(") - self.write(pre) - self.visit(node.operand) - self.write(suf) - self.write(")") - self.write(")") - else: - self.write(pre) - self.write("(") - self.write(op) - self.visit(node.operand) - self.write(")") - self.write(suf) + pre, suf = self.inferCast(node.vhd, node.vhdOri) + if isinstance(node.op, ast.UAdd): + op = "" else: - if isinstance(node.op, ast.USub) and isinstance(node.operand, ast.Num): - node.operand.n = -node.operand.n - node.operand.vhd = node.vhd - self.visit(node.operand) - return + op = opmap[type(node.op)] - pre, suf = self.inferCast(node.vhd, node.vhdOri) - if isinstance(node.op, ast.UAdd): - op = "" - else: - op = opmap[type(node.op)] - - if isinstance(node.operand, ast.Num): - self.write("(") - self.write(op) - self.write("(") - self.write(pre) - self.visit(node.operand) - self.write(suf) - self.write(")") - self.write(")") - else: - self.write(pre) - self.write("(") - self.write(op) - self.visit(node.operand) - self.write(")") - self.write(suf) + if isinstance(node.operand, ast.Constant): + self.write("(") + self.write(op) + self.write("(") + self.write(pre) + self.visit(node.operand) + self.write(suf) + self.write(")") + self.write(")") + else: + self.write(pre) + self.write("(") + self.write(op) + self.visit(node.operand) + self.write(")") + self.write(suf) def visit_Attribute(self, node): if isinstance(node.ctx, ast.Store): @@ -1185,20 +1156,16 @@ class _ConvertVisitor(ast.NodeVisitor, _ConversionMixin): return elif f is ord: opening, closing = '', '' - v = ord(node.args[0].s) - node.args[0].s = v + v = ord(node.args[0].value) + node.args[0].value = v self.write(v) return elif f is int: opening, closing = '', '' pre, suf = self.inferCast(node.vhd, node.vhdOri) # convert number argument to integer - if sys.version_info >= (3, 8, 0): - if isinstance(node.args[0], ast.Constant): - node.args[0].n = int(node.args[0].n) - else: - if isinstance(node.args[0], ast.Num): - node.args[0].n = int(node.args[0].n) + if isinstance(node.args[0], ast.Constant): + node.args[0].n = int(node.args[0].value) elif inspect.isclass(f) and issubclass(f, intbv): pre, post = "", "" arg = node.args[0] @@ -1277,53 +1244,18 @@ class _ConvertVisitor(ast.NodeVisitor, _ConversionMixin): self.visit(right) self.write(suf) - if sys.version_info >= (3, 9, 0): - - def visit_Constant(self, node): - if node.value is None: - # NameConstant - node.id = str(node.value) - self.getName(node) - elif isinstance(node.value, bool): - # NameConstant - node.id = str(node.value) - self.getName(node) - elif isinstance(node.value, int): - # Num - n = node.value - if isinstance(node.vhd, vhd_std_logic): - self.write("'%s'" % n) - elif isinstance(node.vhd, vhd_boolean): - self.write("%s" % bool(n)) - # elif isinstance(node.vhd, (vhd_unsigned, vhd_signed)): - # self.write('"%s"' % tobin(n, node.vhd.size)) - elif isinstance(node.vhd, vhd_unsigned): - if abs(n) < 2 ** 31: - self.write("to_unsigned(%s, %s)" % (n, node.vhd.size)) - else: - self.write('unsigned\'("%s")' % tobin(n, node.vhd.size)) - elif isinstance(node.vhd, vhd_signed): - if abs(n) < 2 ** 31: - self.write("to_signed(%s, %s)" % (n, node.vhd.size)) - else: - self.write('signed\'("%s")' % tobin(n, node.vhd.size)) - else: - if n < 0: - self.write("(") - self.write(n) - if n < 0: - self.write(")") - elif isinstance(node.value, str): - # Str - typemark = 'string' - if isinstance(node.vhd, vhd_unsigned): - typemark = 'unsigned' - self.write("%s'(\"%s\")" % (typemark, node.value)) - - else: - - def visit_Num(self, node): - n = node.n + def visit_Constant(self, node): + if node.value is None: + # NameConstant + node.id = str(node.value) + self.getName(node) + elif isinstance(node.value, bool): + # NameConstant + node.id = str(node.value) + self.getName(node) + elif isinstance(node.value, int): + # Num + n = node.value if isinstance(node.vhd, vhd_std_logic): self.write("'%s'" % n) elif isinstance(node.vhd, vhd_boolean): @@ -1346,16 +1278,12 @@ class _ConvertVisitor(ast.NodeVisitor, _ConversionMixin): self.write(n) if n < 0: self.write(")") - - def visit_Str(self, node): + elif isinstance(node.value, str): + # Str typemark = 'string' if isinstance(node.vhd, vhd_unsigned): typemark = 'unsigned' - self.write("%s'(\"%s\")" % (typemark, node.s)) - - def visit_NameConstant(self, node): - node.id = str(node.value) - self.getName(node) + self.write("%s'(\"%s\")" % (typemark, node.value)) def visit_Continue(self, node, *args): self.write("next;") @@ -1363,17 +1291,13 @@ class _ConvertVisitor(ast.NodeVisitor, _ConversionMixin): def visit_Expr(self, node): expr = node.value # docstrings on unofficial places - if isinstance(expr, ast.Str): - doc = _makeDoc(expr.s, self.ind) + if isinstance(expr, ast.Constant) and isinstance(expr.value, str): + doc = _makeDoc(expr.value, self.ind) self.write(doc) return # skip extra semicolons - if sys.version_info >= (3, 8, 0): - if isinstance(expr, ast.Constant): - return - else: - if isinstance(expr, ast.Num): - return + if isinstance(expr, ast.Constant): + return self.visit(expr) # ugly hack to detect an orphan "task" call if isinstance(expr, ast.Call) and hasattr(expr, 'tree'): @@ -2419,7 +2343,7 @@ class _AnnotateTypesVisitor(ast.NodeVisitor, _ConversionMixin): if f is concat: s = 0 for a in node.args: - if isinstance(a, ast.Str): + if isinstance(a, ast.Constant) and isinstance(a.value, str): a.vhd = vhd_unsigned(a.vhd.size) elif isinstance(a.vhd, vhd_signed): a.vhd = vhd_unsigned(a.vhd.size) @@ -2458,42 +2382,23 @@ class _AnnotateTypesVisitor(ast.NodeVisitor, _ConversionMixin): right.vhd = vhd_signed(right.vhd.size + 1) node.vhdOri = copy(node.vhd) - if sys.version_info >= (3, 9, 0): - - def visit_Constant(self, node): - if node.value is None: - # NameConstant - node.vhd = inferVhdlObj(node.value) - elif isinstance(node.value, bool): - # NameConstant - node.vhd = inferVhdlObj(node.value) - elif isinstance(node.value, int): - # Num - if node.value < 0: - node.vhd = vhd_int() - else: - node.vhd = vhd_nat() - elif isinstance(node.value, str): - # Str - node.vhd = vhd_string() - node.vhdOri = copy(node.vhd) - - else: - - def visit_Str(self, node): - node.vhd = vhd_string() - node.vhdOri = copy(node.vhd) - - def visit_Num(self, node): - if node.n < 0: + def visit_Constant(self, node): + if node.value is None: + # NameConstant + node.vhd = inferVhdlObj(node.value) + elif isinstance(node.value, bool): + # NameConstant + node.vhd = inferVhdlObj(node.value) + elif isinstance(node.value, int): + # Num + if node.value < 0: node.vhd = vhd_int() else: node.vhd = vhd_nat() - node.vhdOri = copy(node.vhd) - - def visit_NameConstant(self, node): - node.vhd = inferVhdlObj(node.value) - node.vhdOri = copy(node.vhd) + elif isinstance(node.value, str): + # Str + node.vhd = vhd_string() + node.vhdOri = copy(node.vhd) def visit_For(self, node): var = node.target.id @@ -2513,7 +2418,7 @@ class _AnnotateTypesVisitor(ast.NodeVisitor, _ConversionMixin): self.inferShiftType(node) elif isinstance(node.op, (ast.BitAnd, ast.BitOr, ast.BitXor)): self.inferBitOpType(node) - elif isinstance(node.op, ast.Mod) and isinstance(node.left, ast.Str): # format string + elif isinstance(node.op, ast.Mod) and isinstance(node.left, ast.Constant) and isinstance(node.left.value, str): # format string pass else: self.inferBinOpType(node) diff --git a/myhdl/conversion/_toVerilog.py b/myhdl/conversion/_toVerilog.py index 6607c95a..71bdaf56 100644 --- a/myhdl/conversion/_toVerilog.py +++ b/myhdl/conversion/_toVerilog.py @@ -858,16 +858,12 @@ class _ConvertVisitor(ast.NodeVisitor, _ConversionMixin): return elif f is ord: opening, closing = '', '' - node.args[0].s = str(ord(node.args[0].s)) + node.args[0].value = str(ord(node.args[0].value)) elif f is int: opening, closing = '', '' # convert number argument to integer - if sys.version_info >= (3, 8, 0): - if isinstance(node.args[0], ast.Constant): - node.args[0].n = int(node.args[0].n) - else: - if isinstance(node.args[0], ast.Num): - node.args[0].n = int(node.args[0].n) + if isinstance(node.args[0], ast.Constant): + node.args[0].value = int(node.args[0].value) elif f in (intbv, modbv): self.visit(node.args[0]) return @@ -919,40 +915,21 @@ class _ConvertVisitor(ast.NodeVisitor, _ConversionMixin): self.write(")") self.context = None - if sys.version_info >= (3, 9, 0): - - def visit_Constant(self, node): - if node.value is None: - # NameConstant - self.write(nameconstant_map[node.obj]) - elif isinstance(node.value, bool): - self.write(nameconstant_map[node.obj]) - elif isinstance(node.value, int): - # Num - if self.context == _context.PRINT: - self.write('"%s"' % node.value) - else: - self.write(self.IntRepr(node.value)) - elif isinstance(node.value, str): - # Str - s = node.value - if self.context == _context.PRINT: - self.write('"%s"' % s) - elif len(s) == s.count('0') + s.count('1'): - self.write("%s'b%s" % (len(s), s)) - else: - self.write(s) - - else: - - def visit_Num(self, node): + def visit_Constant(self, node): + if node.value is None: + # NameConstant + self.write(nameconstant_map[node.obj]) + elif isinstance(node.value, bool): + self.write(nameconstant_map[node.obj]) + elif isinstance(node.value, int): + # Num if self.context == _context.PRINT: - self.write('"%s"' % node.n) + self.write('"%s"' % node.value) else: - self.write(self.IntRepr(node.n)) - - def visit_Str(self, node): - s = node.s + self.write(self.IntRepr(node.value)) + elif isinstance(node.value, str): + # Str + s = node.value if self.context == _context.PRINT: self.write('"%s"' % s) elif len(s) == s.count('0') + s.count('1'): @@ -960,26 +937,19 @@ class _ConvertVisitor(ast.NodeVisitor, _ConversionMixin): else: self.write(s) - def visit_NameConstant(self, node): - self.write(nameconstant_map[node.obj]) - def visit_Continue(self, node): self.write("disable %s;" % self.labelStack[-1]) def visit_Expr(self, node): expr = node.value # docstrings on unofficial places - if isinstance(expr, ast.Str): - doc = _makeDoc(expr.s, self.ind) + if isinstance(expr, ast.Constant) and isinstance(expr.value, str): + doc = _makeDoc(expr.value, self.ind) self.write(doc) return # skip extra semicolons - if sys.version_info >= (3, 8, 0): - if isinstance(expr, ast.Constant): - return - else: - if isinstance(expr, ast.Num): - return + if isinstance(expr, ast.Constant): + return self.visit(expr) # ugly hack to detect an orphan "task" call if isinstance(expr, ast.Call) and hasattr(expr, 'tree'): @@ -1708,12 +1678,8 @@ class _AnnotateTypesVisitor(ast.NodeVisitor, _ConversionMixin): node.signed = node.operand.signed if isinstance(node.op, ast.USub): node.obj = int(-1) - if sys.version_info >= (3, 8, 0): - if isinstance(node.operand, ast.Constant): - node.signed = True - else: - if isinstance(node.operand, ast.Num): - node.signed = True + if isinstance(node.operand, ast.Constant): + node.signed = True def visit_Attribute(self, node): if isinstance(node.ctx, ast.Store): @@ -1753,21 +1719,8 @@ class _AnnotateTypesVisitor(ast.NodeVisitor, _ConversionMixin): return self.generic_visit(node) - if sys.version_info >= (3, 9, 0): - - def visit_Constant(self, node): - node.signed = False - - else: - - def visit_Num(self, node): - node.signed = False - - def visit_Str(self, node): - node.signed = False - - def visit_NameConstant(self, node): - node.signed = False + def visit_Constant(self, node): + node.signed = False def visit_Name(self, node): if isinstance(node.ctx, ast.Store): diff --git a/myhdl/test/conversion/general/test_ShadowSignal.py b/myhdl/test/conversion/general/test_ShadowSignal.py index 8aca8c54..d59860f2 100644 --- a/myhdl/test/conversion/general/test_ShadowSignal.py +++ b/myhdl/test/conversion/general/test_ShadowSignal.py @@ -13,6 +13,7 @@ def bench_SliceSignal(): @instance def check(): + ''' Running bench_SliceSignal ''' for i in range(N): s.next = i yield delay(10) diff --git a/setup.py b/setup.py index a3338e2e..690729a3 100644 --- a/setup.py +++ b/setup.py @@ -51,7 +51,7 @@ setup( license="LGPL", platforms='any', keywords="HDL ASIC FPGA hardware design", - python_requires='>=3.7', + python_requires='>=3.8', classifiers=[ 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', @@ -60,10 +60,11 @@ setup( 'Operating System :: OS Independent', 'Programming Language :: Python', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', + 'Programming Language :: Python :: 3.12', 'Programming Language :: Python :: 3 :: Only', ] )