Skip to content

Commit

Permalink
try to get unittest of RecursionError working under "pytest -s tests/"
Browse files Browse the repository at this point in the history
  • Loading branch information
artgoldberg committed Dec 13, 2020
1 parent faba24d commit 43b0962
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 21 deletions.
Binary file modified examples/kinetic_metabolic_model/template.xlsx
Binary file not shown.
Binary file modified examples/merged_metabolic_model/delta-g-vs-k-cat.pdf
Binary file not shown.
32 changes: 14 additions & 18 deletions obj_tables/math/expression.py
Original file line number Diff line number Diff line change
Expand Up @@ -1453,9 +1453,9 @@ def _validate(self):
self._remove_subtraction()
self._multiply_numbers()
except RecursionError as e:
error = (f"\nast or LinearParsedExpressionValidator._validate() failed while processing "
error = (f"\nRecursionError in ast or LinearParsedExpressionValidator._validate() while processing "
f"{self.parsed_expression.model_cls.__name__} '{self.expression}'"
"\ndecrease number of expression terms, or increase call stack with sys.setrecursionlimit(); "
"\ndecrease the num. of expression terms, or raise the call stack size with sys.setrecursionlimit(); "
"if needed, increase available memory")
raise ParsedExpressionError(str(e) + error)

Expand Down Expand Up @@ -1528,28 +1528,24 @@ def visit_BinOp(self, node):
(isinstance(node.left, ast.BinOp) and
isinstance(node.left.op, (ast.Add, ast.Sub))))):
# distribute mult. with +/- on left: (a +/- b) * c
left = ast.BinOp(left=node.left.left,
op=ast.Mult(),
right=node.right)
right = ast.BinOp(left=node.left.right,
op=ast.Mult(),
right=node.right)
return ast.BinOp(left=left,
right=right,
return ast.BinOp(left=ast.BinOp(left=node.left.left,
op=ast.Mult(),
right=node.right),
right=ast.BinOp(left=node.left.right,
op=ast.Mult(),
right=node.right),
op=node.left.op)
if (isinstance(node.op, ast.Mult) and
(isinstance(node.left, (ast.Num, ast.Name, ast.UnaryOp, ast.BinOp)) and
(isinstance(node.right, ast.BinOp) and
isinstance(node.right.op, (ast.Add, ast.Sub))))):
# distribute mult. with +/- on right: a * (b +/- c)
left = ast.BinOp(left=node.left,
op=ast.Mult(),
right=node.right.left)
right = ast.BinOp(left=node.left,
op=ast.Mult(),
right=node.right.right)
return ast.BinOp(left=left,
right=right,
return ast.BinOp(left=ast.BinOp(left=node.left,
op=ast.Mult(),
right=node.right.left),
right=ast.BinOp(left=node.left,
op=ast.Mult(),
right=node.right.right),
op=node.right.op)
return node

Expand Down
10 changes: 7 additions & 3 deletions tests/math/test_math_expression.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"""

import astor
import gc
import mock
import random
import re
Expand Down Expand Up @@ -1362,14 +1363,17 @@ def test_validate(self):
self.assertTrue(valid)
self.assertTrue(error is None)

linear_expression = '3 * r - 4*r_back'
def test_validate_exception(self):
linear_expression = base_linear_expression = '3 * r - 4 * r_back + 2 * r_for'
# blow up size of expression to raise RecursionError
with self.assertRaisesRegex(ParsedExpressionError, 'ast or LinearParsedExpressionValidator._validate.* failed'):
with self.assertRaisesRegex(ParsedExpressionError,
'RecursionError in ast or LinearParsedExpressionValidator._validate'):
while True:
parsed_expr = ParsedExpression(FunctionExpression, 'attr', linear_expression, self.test_objects)
parsed_expr.tokenize()
valid, error = LinearParsedExpressionValidator().validate(parsed_expr)
linear_expression = f"{linear_expression} + {linear_expression}"
linear_expression = f"{linear_expression} + {base_linear_expression}"
gc.collect()

def test__expr_has_constants_right_of_variables(self):

Expand Down

0 comments on commit 43b0962

Please sign in to comment.