Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Precedences for Del, DifferentialD and CapitalDifferentialD #100

Merged
merged 7 commits into from
Nov 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ inputrc-unicode:
#: Run Mathics core checks
check-mathics::
MATHICS_CHARACTER_ENCODING="ASCII" $(PYTHON) -m mathics.docpipeline $o
pytest test/test_mathics_precedence.py

#: Remove ChangeLog
rmChangeLog:
Expand Down
1 change: 0 additions & 1 deletion mathics_scanner/data/named-characters.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6920,7 +6920,6 @@ Nor:
has-unicode-inverse: false
is-letter-like: false
operator-name: Nor
# No precedences since this gets transformed to Not[Or[expr]]
unicode-equivalent: "\u22BD"
unicode-equivalent-name: NOR
unicode-reference: https://www.compart.com/en/unicode/U+22BD
Expand Down
4 changes: 2 additions & 2 deletions mathics_scanner/data/operators.yml
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,7 @@ Cap:

CapitalDifferentialD:
Precedence-Function: 550
precedence: 560
precedence: 550
WolframLanguageData:
WolframLanguageData-corrected: 23
UnicodeCharacters.tr: 630
Expand Down Expand Up @@ -1119,7 +1119,7 @@ DifferenceDelta:

DifferentialD:
Precedence-Function: 550
precedence: 560
precedence: 550
WolframLanguageData:
WolframLanguageData-corrected: 23
UnicodeCharacters.tr: 630
Expand Down
168 changes: 168 additions & 0 deletions test/mathics_helper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
# -*- coding: utf-8 -*-
import os.path as osp
import time
from typing import Optional

from mathics.core.load_builtin import import_and_load_builtins
from mathics.session import MathicsSession

import_and_load_builtins()

# Set up a Mathics session with definitions.
# For consistency set the character encoding ASCII which is
# the lowest common denominator available on all systems.
session = MathicsSession(character_encoding="ASCII")

# Set up a data path that can be used in testing
data_dir = osp.normpath(osp.join(osp.dirname(__file__), "data"))


def reset_session(add_builtin=True, catch_interrupt=False):
"""
reset the session cleaning all the definitions.
"""
global session
session.reset()
session.evaluate("SetDirectory[$TemporaryDirectory];")


def evaluate_value(str_expr: str):
return session.evaluate(str_expr).value


def evaluate(str_expr: str):
return session.evaluate(str_expr)


def check_evaluation(
str_expr: Optional[str],
str_expected: Optional[str] = None,
failure_message: str = "",
hold_expected: bool = False,
to_string_expr: bool = True,
to_string_expected: bool = True,
to_python_expected: bool = False,
expected_messages: Optional[tuple] = None,
):
"""
Helper function to test Mathics expression against
its results.

Compares the expressions represented by ``str_expr`` and ``str_expected`` by
evaluating the first, and optionally, the second. If omitted, `str_expected`
is assumed to be `"Null"`.

str_expr: The expression to be tested. If its value is ``None``, the session is
reset.
At the beginning of each set of pytests, it is important to call
``check_evaluation(None)`` to avoid that definitions introduced by
other tests affect the results.

str_expected: The expected result. The value ``None`` is equivalent to ``"Null"``.

failure_message: message shown in case of failure. Use "" for no failure message.

hold_expected: If ``False`` (default value) the ``str_expected`` is evaluated.
Otherwise, the expression is considered literally.

to_string_expr: If ``True`` (default value) the result of the evaluation is
converted into a Python string. Otherwise, the expression is kept
as an Expression object.
If this argument is set to ``None``, the session is reset.

to_string_expected: If ``True`` (default value) the expected expression is
evaluated and then converted to a Python string. result of the
evaluation is converted into a Python string.
If ``False``, the expected expression is kept as an Expression
object.

to_python_expected: If ``True``, and ``to_string_expected`` is ``False``, the result
of evaluating ``str_expr``is compared against the result of the
evaluation of ``str_expected``, converted into a
Python object.

expected_messages: If a tuple of strings are passed into
this parameter, messages and prints raised during
the evaluation of ``str_expr`` are compared with the elements of
the list. If ``None``, this comparison
is omitted.
"""
if str_expr is None:
reset_session()
return
if str_expected is None:
str_expected = "Null"

if to_string_expr:
str_expr = f"ToString[{str_expr}]"
result = evaluate_value(str_expr)
else:
result = evaluate(str_expr)

outs = [out.text for out in session.evaluation.out]

if to_string_expected:
if hold_expected:
expected = str_expected
else:
str_expected = f"ToString[{str_expected}]"
expected = evaluate_value(str_expected)
else:
if hold_expected:
if to_python_expected:
expected = str_expected
else:
expected = evaluate(f"HoldForm[{str_expected}]").elements[0]
else:
expected = evaluate(str_expected)
if to_python_expected:
expected = expected.to_python(string_quotes=False)

print(time.asctime())
if failure_message:
print((result, expected))
assert result == expected, failure_message
else:
print((result, expected))
assert result == expected

if expected_messages is not None:
msgs = list(expected_messages)
expected_len = len(msgs)
got_len = len(outs)
assert (
expected_len == got_len
), f"expected {expected_len}; got {got_len}. Messages: {outs}"
for out, msg in zip(outs, msgs):
if out != msg:
print(f"out:<<{out}>>")
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
Loading
Loading