Skip to content

Commit

Permalink
This PR implements a method in the MathicsSession class that uses the…
Browse files Browse the repository at this point in the history
… Evaluation.evaluate method. This allows to handle exceptions and special symbols like % or Line references. This method is used in certain pytests.
  • Loading branch information
mmatera committed Oct 17, 2023
1 parent 3a65cc9 commit e9a6bf0
Show file tree
Hide file tree
Showing 7 changed files with 59 additions and 89 deletions.
8 changes: 8 additions & 0 deletions mathics/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,13 +86,21 @@ def reset(self, add_builtin=True, catch_interrupt=False):
self.last_result = None

def evaluate(self, str_expression, timeout=None, form=None):
"""Parse str_expression and evaluate using the `evaluate` method of the Expression"""
self.evaluation.out.clear()
expr = parse(self.definitions, MathicsSingleLineFeeder(str_expression))
if form is None:
form = self.form
self.last_result = expr.evaluate(self.evaluation)
return self.last_result

def evaluate_as_in_cli(self, str_expression, timeout=None, form=None):
"""This method parse and evaluate the expression using the session.evaluation.evaluate method"""
query = self.evaluation.parse(str_expression)
res = self.evaluation.evaluate(query)
self.evaluation.stopped = False
return res

def format_result(self, str_expression=None, timeout=None, form=None):
if str_expression:
self.evaluate(str_expression, timeout=None, form=None)
Expand Down
28 changes: 2 additions & 26 deletions test/builtin/test_attributes.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"""

import os
from test.helper import check_evaluation, session
from test.helper import check_evaluation, check_evaluation_as_in_cli, session

import pytest

Expand Down Expand Up @@ -282,28 +282,4 @@ def test_private_doctests_attributes_with_exceptions(
str_expr, msgs, str_expected, fail_msg
):
"""These tests check the behavior of $RecursionLimit and $IterationLimit"""

# Here we do not use the session object to check the messages
# produced by the exceptions. If $RecursionLimit / $IterationLimit
# are reached during the evaluation using a MathicsSession object,
# an exception is raised. On the other hand, using the `Evaluation.evaluate`
# method, the exception is handled.
#
# TODO: Maybe it makes sense to clone this exception handling in
# the check_evaluation function.
#
def eval_expr(expr_str):
query = session.evaluation.parse(expr_str)
res = session.evaluation.evaluate(query)
session.evaluation.stopped = False
return res

res = eval_expr(str_expr)
if msgs is None:
assert len(res.out) == 0
else:
assert len(res.out) == len(msgs)
for li1, li2 in zip(res.out, msgs):
assert li1.text == li2

assert res.result == str_expected
check_evaluation_as_in_cli(str_expr, str_expected, fail_msg, msgs)
28 changes: 2 additions & 26 deletions test/builtin/test_evalution.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"""


from test.helper import check_evaluation, session
from test.helper import check_evaluation_as_in_cli, session

import pytest

Expand Down Expand Up @@ -66,28 +66,4 @@
)
def test_private_doctests_evaluation(str_expr, msgs, str_expected, fail_msg):
"""These tests check the behavior of $RecursionLimit and $IterationLimit"""

# Here we do not use the session object to check the messages
# produced by the exceptions. If $RecursionLimit / $IterationLimit
# are reached during the evaluation using a MathicsSession object,
# an exception is raised. On the other hand, using the `Evaluation.evaluate`
# method, the exception is handled.
#
# TODO: Maybe it makes sense to clone this exception handling in
# the check_evaluation function.
#
def eval_expr(expr_str):
query = session.evaluation.parse(expr_str)
res = session.evaluation.evaluate(query)
session.evaluation.stopped = False
return res

res = eval_expr(str_expr)
if msgs is None:
assert len(res.out) == 0
else:
assert len(res.out) == len(msgs)
for li1, li2 in zip(res.out, msgs):
assert li1.text == li2

assert res.result == str_expected
check_evaluation_as_in_cli(str_expr, str_expected, fail_msg, msgs)
19 changes: 2 additions & 17 deletions test/builtin/test_functional.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import sys
import time
from test.helper import check_evaluation, evaluate, session
from test.helper import check_evaluation, check_evaluation_as_in_cli, evaluate, session

import pytest

Expand Down Expand Up @@ -95,22 +95,7 @@
)
def test_private_doctests_apply_fns_to_lists(str_expr, msgs, str_expected, fail_msg):
"""functional.apply_fns_to_lists"""

def eval_expr(expr_str):
query = session.evaluation.parse(expr_str)
res = session.evaluation.evaluate(query)
session.evaluation.stopped = False
return res

res = eval_expr(str_expr)
if msgs is None:
assert len(res.out) == 0
else:
assert len(res.out) == len(msgs)
for li1, li2 in zip(res.out, msgs):
assert li1.text == li2

assert res.result == str_expected
check_evaluation_as_in_cli(str_expr, str_expected, fail_msg, msgs)


@pytest.mark.parametrize(
Expand Down
19 changes: 2 additions & 17 deletions test/builtin/test_messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"""


from test.helper import check_evaluation, session
from test.helper import check_evaluation_as_in_cli, session

import pytest

Expand Down Expand Up @@ -136,19 +136,4 @@
)
def test_private_doctests_messages(str_expr, msgs, str_expected, fail_msg):
"""These tests check the behavior the module messages"""

def eval_expr(expr_str):
query = session.evaluation.parse(expr_str)
res = session.evaluation.evaluate(query)
session.evaluation.stopped = False
return res

res = eval_expr(str_expr)
if msgs is None:
assert len(res.out) == 0
else:
assert len(res.out) == len(msgs)
for li1, li2 in zip(res.out, msgs):
assert li1.text == li2

assert res.result == str_expected
check_evaluation_as_in_cli(str_expr, str_expected, fail_msg, msgs)
17 changes: 15 additions & 2 deletions test/builtin/test_procedural.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Unit tests from mathics.builtin.procedural.
"""

from test.helper import check_evaluation, session
from test.helper import check_evaluation, check_evaluation_as_in_cli, session

import pytest

Expand Down Expand Up @@ -111,6 +111,19 @@ def test_private_doctests_procedural(str_expr, msgs, str_expected, fail_msg):

def test_history_compound_expression():
"""Test the effect in the history from the evaluation of a CompoundExpression"""
check_evaluation_as_in_cli("Clear[x];Clear[y]")
check_evaluation_as_in_cli("CompoundExpression[x, y, Null]")
check_evaluation_as_in_cli("ToString[%]", "y")
check_evaluation_as_in_cli(
"CompoundExpression[CompoundExpression[y, x, Null], Null]"
)
check_evaluation_as_in_cli("ToString[%]", "x")
check_evaluation_as_in_cli("CompoundExpression[x, y, Null, Null]")
check_evaluation_as_in_cli("ToString[%]", "y")
check_evaluation_as_in_cli("CompoundExpression[]")
check_evaluation_as_in_cli("ToString[%]", "Null")
check_evaluation_as_in_cli("Clear[x];Clear[y];")
return

def eval_expr(expr_str):
query = session.evaluation.parse(expr_str)
Expand All @@ -119,7 +132,7 @@ def eval_expr(expr_str):
eval_expr("Clear[x];Clear[y]")
eval_expr("CompoundExpression[x, y, Null]")
assert eval_expr("ToString[%]").result == "y"
eval_expr("CompoundExpression[CompoundExpression[y, x, Null], Null]")
eval_expr("CompoundExpression[CompoundExpression[y, x, Null], Null])")
assert eval_expr("ToString[%]").result == "x"
eval_expr("CompoundExpression[x, y, Null, Null]")
assert eval_expr("ToString[%]").result == "y"
Expand Down
29 changes: 28 additions & 1 deletion test/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def evaluate(str_expr: str):


def check_evaluation(
str_expr: str,
str_expr: Optional[str],
str_expected: Optional[str] = None,
failure_message: str = "",
hold_expected: bool = False,
Expand Down Expand Up @@ -122,3 +122,30 @@ def check_evaluation(
print(" and ")
print(f"expected=<<{msg}>>")
assert False, " do not match."


def check_evaluation_as_in_cli(
str_expr: Optional[str] = None,
str_expected: Optional[str] = None,
failure_message: str = "",
expected_messages: Optional[tuple] = None,
):
"""
Use this method when special Symbols like Return, %, %%,
$IterationLimit, $RecursionLimit, etc. are used in the tests.
"""
if str_expr is None:
reset_session()
return

res = session.evaluate_as_in_cli(str_expr)
if expected_messages is None:
assert len(res.out) == 0
else:
assert len(res.out) == len(expected_messages)
for li1, li2 in zip(res.out, expected_messages):
assert li1.text == li2

if failure_message:
assert res.result == str_expected, failure_message
assert res.result == str_expected

0 comments on commit e9a6bf0

Please sign in to comment.