Skip to content

Commit 0c1e8c1

Browse files
authored
More trace evaluation filtering (#1410)
1 parent 87f24f1 commit 0c1e8c1

2 files changed

Lines changed: 115 additions & 22 deletions

File tree

mathics/eval/tracing.py

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -29,30 +29,39 @@ def skip_trivial_evaluation(expr, status: str, orig_expr=None) -> bool:
2929
"""
3030
from mathics.core.symbols import Symbol, SymbolConstant
3131

32-
if isinstance(expr, Symbol) and not isinstance(expr, SymbolConstant):
33-
return True
34-
35-
if (
36-
status == "Returning"
37-
and hasattr(expr, "is_literal")
38-
and expr.is_literal
39-
and hasattr(orig_expr, "is_literal")
40-
and orig_expr.is_literal
41-
):
42-
return True
43-
44-
if orig_expr == expr:
45-
# If the two expressions are the same, there is no point in
46-
# repeating the output.
47-
return True
32+
if status == "Returning":
33+
if (
34+
hasattr(expr, "is_literal")
35+
and expr.is_literal
36+
and hasattr(orig_expr, "is_literal")
37+
and orig_expr.is_literal
38+
):
39+
return True
40+
pass
41+
if isinstance(expr, Symbol) and not isinstance(expr, SymbolConstant):
42+
# Evaluation of a symbol, like Plus isn't that interesting
43+
return True
44+
45+
else:
46+
# Status != "Returning", i.e. executing
47+
48+
if isinstance(expr, Symbol):
49+
# Evaluation of a symbol, like Plus isn't that interesting
50+
return True
51+
52+
if orig_expr == expr:
53+
# If the two expressions are the same, there is no point in
54+
# repeating the output.
55+
return True
4856

4957
return False
5058

5159

5260
def print_evaluate(expr, evaluation, status: str, fn: Callable, orig_expr=None):
5361
"""
5462
Called from a decorated Python @trace_evaluate .evaluate()
55-
method when TraceActivate["evaluate" -> True]
63+
method when TraceActivate["evaluate" -> True] or
64+
running TraceEvaluation.
5665
"""
5766

5867
if evaluation.definitions.timing_trace_evaluation:
@@ -64,7 +73,8 @@ def print_evaluate(expr, evaluation, status: str, fn: Callable, orig_expr=None):
6473
indents = " " * evaluation.recursion_depth
6574

6675
if orig_expr is not None:
67-
if fn.__name__ == "rewrite_apply_eval_step":
76+
fn_name = fn.__name__ if hasattr(fn, "__name__") else None
77+
if fn_name == "rewrite_apply_eval_step":
6878
assert isinstance(expr, tuple)
6979
if orig_expr != expr[0]:
7080
if status == "Returning":
@@ -120,7 +130,13 @@ def wrapper(expr, evaluation) -> Any:
120130
if not skip_call:
121131
result = func(expr, evaluation)
122132
if trace_evaluate_on_return is not None and not was_boxing:
123-
trace_evaluate_on_return(result, evaluation, "Returning", expr, result)
133+
trace_evaluate_on_return(
134+
expr=result,
135+
evaluation=evaluation,
136+
status="Returning",
137+
fn=expr,
138+
orig_expr=expr,
139+
)
124140
evaluation.is_boxing = was_boxing
125141
return result
126142

test/builtin/test_trace.py

Lines changed: 80 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,17 @@
22
"""
33
Unit tests for mathics.builtin.trace
44
"""
5-
from inspect import isfunction
6-
from test.helper import evaluate
7-
from typing import Callable
5+
from inspect import isfunction, ismethod
6+
from test.helper import evaluate, session
7+
from typing import Any, Callable
88

99
import pytest
1010

1111
import mathics.eval.tracing
1212
from mathics import version_info
1313
from mathics.core.evaluation import Evaluation
1414
from mathics.core.interrupt import AbortInterrupt
15+
from mathics.eval.tracing import TraceEvent
1516

1617
trace_evaluation_calls = 0
1718

@@ -68,3 +69,79 @@ def counting_print_evaluate(
6869
mathics.eval.tracing.print_evaluate = old_evaluation_hook
6970
old_recursion_limit = evaluate(f"$RecursionLimit = {old_recursion_limit.value}")
7071
assert mathics.eval.tracing.print_evaluate == old_evaluation_hook
72+
73+
74+
event_queue = []
75+
76+
77+
def test_skip_trivial_evaluation():
78+
"""
79+
Test of TraceEvaluate[] to filter events
80+
"""
81+
82+
def empty_queue():
83+
global event_queue
84+
event_queue = []
85+
86+
def call_event_func(event: TraceEvent, fn: Callable, *args) -> bool:
87+
"""
88+
Capture filtered calls in event_queue.
89+
"""
90+
if isinstance(type(fn), type) or ismethod(fn) or isfunction(fn):
91+
name = f"{fn.__module__}.{fn.__qualname__}"
92+
else:
93+
name = str(fn)
94+
event_queue.append(f"{event.name} call : {name}{args[:3]}")
95+
return False
96+
97+
def return_event_func(event: TraceEvent, result: Any) -> Any:
98+
"""
99+
A somewhat generic function to print a traced call's
100+
return value.
101+
"""
102+
event_queue.append(f"{event.name} result: {result}")
103+
return result
104+
105+
def capture_print(s: str):
106+
"""
107+
A somewhat generic function to print a traced call's
108+
return value.
109+
"""
110+
event_queue.append(s)
111+
112+
session.reset()
113+
old_print_out = session.evaluation.print_out
114+
session.evaluation.print_out = capture_print
115+
empty_queue()
116+
117+
try:
118+
session.evaluate("TraceEvaluation[2 3 + 4]")
119+
assert [
120+
" Evaluating: System`Plus[System`Times[2, 3], 4]",
121+
" Evaluating: System`Times[2, 3]",
122+
" Returning: System`Times[2, 3] = (<Integer: 6>, False)",
123+
" Returning: System`Times[2, 3] = 6",
124+
" Returning: System`Plus[System`Times[2, 3], 4] = (<Integer: 10>, False)",
125+
" Returning: System`Plus[System`Times[2, 3], 4] = 10",
126+
] == event_queue
127+
# print()
128+
# for line in event_queue:
129+
# print(line)
130+
131+
empty_queue()
132+
session.evaluate("TraceEvaluation[(2 + 3) 4]")
133+
assert [
134+
" Evaluating: System`Times[System`Plus[2, 3], 4]"
135+
" Evaluating: System`Plus[2, 3]",
136+
" Returning: System`Plus[2, 3] = (<Integer: 5>, False)",
137+
" Returning: System`Plus[2, 3] = 5",
138+
" Returning: System`Times[System`Plus[2, 3], 4] = (<Integer: 20>, False)",
139+
]
140+
# print()
141+
# for line in event_queue:
142+
# print(line)
143+
144+
finally:
145+
# Just in case, restore everything back to what it was before running this test.
146+
session.evaluation.print_out = old_print_out
147+
session.reset()

0 commit comments

Comments
 (0)