Skip to content

Commit

Permalink
Remove deprecated ast classes/attributes
Browse files Browse the repository at this point in the history
ast.NameConstant and node.n raise deprecation warnings with Python 3.12 and will be removed in 3.14
  • Loading branch information
mstimberg committed Aug 2, 2023
1 parent 616bfac commit 69ac986
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 73 deletions.
26 changes: 7 additions & 19 deletions brian2/codegen/optimisation.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,14 +167,14 @@ def _replace_with_zero(zero_node, node):
Parameters
----------
zero_node : `ast.Num`
zero_node : `ast.Constant`
The node to replace
node : `ast.Node`
The node that determines the type
Returns
-------
zero_node : `ast.Num`
zero_node : `ast.Constant`
The original ``zero_node`` with its value replaced by 0 or 0.0.
"""
# must not change the dtype of the output,
Expand Down Expand Up @@ -244,10 +244,7 @@ def render_node(self, node):
else:
val = prefs.core.default_float_dtype(val)
if node.dtype != "boolean":
if hasattr(ast, "Constant"):
newnode = ast.Constant(val)
else:
newnode = ast.Num(val)
newnode = ast.Constant(val)
newnode.dtype = node.dtype
newnode.scalar = True
newnode.stateless = node.stateless
Expand Down Expand Up @@ -588,10 +585,7 @@ def collect(node):
# if the fully evaluated node is just the identity/null element then we
# don't have to make it into an explicit term
if x != op_null:
if hasattr(ast, "Constant"):
num_node = ast.Constant(x)
else:
num_node = ast.Num(x)
num_node = ast.Constant(x)
else:
num_node = None
terms_primary = remaining_terms_primary
Expand All @@ -612,22 +606,16 @@ def collect(node):
node = reduced_node([node, prod_primary], op_primary)
if prod_inverted is not None:
if node is None:
if hasattr(ast, "Constant"):
node = ast.Constant(op_null_with_dtype)
else:
node = ast.Num(op_null_with_dtype)
node = ast.Constant(op_null_with_dtype)
node = ast.BinOp(node, op_inverted(), prod_inverted)

if node is None: # everything cancelled
if hasattr(ast, "Constant"):
node = ast.Constant(op_null_with_dtype)
else:
node = ast.Num(op_null_with_dtype)
node = ast.Constant(op_null_with_dtype)
if (
hasattr(node, "dtype")
and dtype_hierarchy[node.dtype] < dtype_hierarchy[orignode_dtype]
):
node = ast.BinOp(ast.Num(op_null_with_dtype), op_primary(), node)
node = ast.BinOp(ast.Constant(op_null_with_dtype), op_primary(), node)
node.collected = True
return node

Expand Down
2 changes: 1 addition & 1 deletion brian2/parsing/bast.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ def render_Num(self, node):
node.stateless = True
return node

def render_Constant(self, node): # For literals in Python 3.8
def render_Constant(self, node): # For literals in Python >= 3.8
if node.value is True or node.value is False or node.value is None:
return self.render_NameConstant(node)
else:
Expand Down
35 changes: 5 additions & 30 deletions brian2/parsing/expressions.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import ast

from brian2.core.functions import Function
from brian2.parsing.rendering import NodeRenderer
from brian2.parsing.rendering import NodeRenderer, get_node_value
from brian2.units.fundamentalunits import (
DIMENSIONLESS,
DimensionMismatchError,
Expand Down Expand Up @@ -70,10 +70,7 @@ def is_boolean_expression(expr, variables):
raise SyntaxError(
"Expression ought to be boolean but is not (e.g. 'x<y and 3')"
)
elif expr.__class__ in [
getattr(ast, "NameConstant", None),
getattr(ast, "Constant", None),
]:
elif expr.__class__ is ast.Constant:
value = expr.value
if value is True or value is False:
return True
Expand Down Expand Up @@ -140,21 +137,8 @@ def _get_value_from_expression(expr, variables):
return 1.0 if name == "True" else 0.0
else:
raise ValueError(f"Unknown identifier {name}")
elif expr.__class__ is getattr(ast, "NameConstant", None):
value = expr.value
if value is True or value is False:
return 1.0 if value else 0.0
else:
raise ValueError(f"Do not know how to deal with value {value}")
elif expr.__class__ is ast.Num or expr.__class__ is getattr(
ast, "Constant", None
): # Python 3.8
# In Python 3.8, boolean values are represented by Constant, not by
# NameConstant
if expr.n is True or expr.n is False:
return 1.0 if expr.n else 0.0
else:
return expr.n
elif expr.__class__ is ast.Constant:
return get_node_value(expr)
elif expr.__class__ is ast.BoolOp:
raise SyntaxError(
"Cannot determine the numerical value for a boolean operation."
Expand Down Expand Up @@ -231,13 +215,6 @@ def parse_expression_dimensions(expr, variables, orig_expr=None):
orig_expr = expr
mod = ast.parse(expr, mode="eval")
expr = mod.body
if expr.__class__ is getattr(ast, "NameConstant", None):
# new class for True, False, None in Python 3.4
value = expr.value
if value is True or value is False:
return DIMENSIONLESS
else:
raise ValueError(f"Do not know how to handle value {value}")
if expr.__class__ is ast.Name:
name = expr.id
# Raise an error if a function is called as if it were a variable
Expand All @@ -253,9 +230,7 @@ def parse_expression_dimensions(expr, variables, orig_expr=None):
return DIMENSIONLESS
else:
raise KeyError(f"Unknown identifier {name}")
elif expr.__class__ is ast.Num or expr.__class__ is getattr(
ast, "Constant", None
): # Python 3.8
elif expr.__class__ is ast.Constant:
return DIMENSIONLESS
elif expr.__class__ is ast.BoolOp:
# check that the units are valid in each subexpression
Expand Down
37 changes: 14 additions & 23 deletions brian2/parsing/rendering.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,14 @@

def get_node_value(node):
"""Helper function to mask differences between Python versions"""
value = getattr(node, "n", getattr(node, "value", None))
try:
value = node.value
except AttributeError:
try:
value = node.n
except AttributeError:
value = None

if value is None:
raise AttributeError(f'Node {node} has neither "n" nor "value" attribute')
return value
Expand Down Expand Up @@ -83,20 +90,14 @@ def render_node(self, node):
def render_func(self, node):
return self.render_Name(node)

def render_NameConstant(self, node):
return str(node.value)

def render_Name(self, node):
return node.id

def render_Num(self, node):
return repr(get_node_value(node))

def render_Constant(self, node): # For literals in Python 3.8
if node.value is True or node.value is False or node.value is None:
return self.render_NameConstant(node)
else:
return self.render_Num(node)
def render_Constant(self, node):
return self.render_Num(node)

def render_Call(self, node):
if len(node.keywords):
Expand All @@ -121,7 +122,7 @@ def render_element_parentheses(self, node):
Render an element with parentheses around it or leave them away for
numbers, names and function calls.
"""
if node.__class__.__name__ in ["Name", "NameConstant"]:
if node.__class__.__name__ == "Name":
return self.render_node(node)
elif (
node.__class__.__name__ in ["Num", "Constant"] and get_node_value(node) >= 0
Expand Down Expand Up @@ -271,17 +272,11 @@ def render_Name(self, node):
else:
return sympy.Symbol(node.id, real=True)

def render_NameConstant(self, node):
if node.value in [True, False]:
return node.value
else:
return str(node.value)

def render_Num(self, node):
if isinstance(node.n, numbers.Integral):
return sympy.Integer(node.n)
if isinstance(get_node_value(node), numbers.Integral):
return sympy.Integer(get_node_value(node))
else:
return sympy.Float(node.n)
return sympy.Float(get_node_value(node))

def render_BinOp(self, node):
op_name = node.op.__class__.__name__
Expand Down Expand Up @@ -355,10 +350,6 @@ def render_BinOp(self, node):
else:
return NodeRenderer.render_BinOp(self, node)

def render_NameConstant(self, node):
# In Python 3.4, None, True and False go here
return {True: "true", False: "false"}.get(node.value, node.value)

def render_Name(self, node):
# Replace Python's True and False with their C++ bool equivalents
return {"True": "true", "False": "false", "inf": "INFINITY"}.get(
Expand Down

0 comments on commit 69ac986

Please sign in to comment.