Skip to content

Commit

Permalink
Move private doctests to pytest7 (#912)
Browse files Browse the repository at this point in the history
and another one
  • Loading branch information
mmatera authored Sep 9, 2023
1 parent e2af6c8 commit 0cdc458
Show file tree
Hide file tree
Showing 9 changed files with 312 additions and 153 deletions.
23 changes: 0 additions & 23 deletions mathics/builtin/attributes.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,29 +203,6 @@ class Flat(Predefined):
'Flat' is taken into account in pattern matching:
>> f[a, b, c] /. f[a, b] -> d
= f[d, c]
#> SetAttributes[{u, v}, Flat]
#> u[x_] := {x}
#> u[]
= u[]
#> u[a]
= {a}
#> u[a, b]
: Iteration limit of 1000 exceeded.
= $Aborted
#> u[a, b, c]
: Iteration limit of 1000 exceeded.
= $Aborted
#> v[x_] := x
#> v[]
= v[]
#> v[a]
= a
#> v[a, b] (* in Mathematica: Iteration limit of 4096 exceeded. *)
= v[a, b]
#> v[a, b, c] (* in Mathematica: Iteration limit of 4096 exceeded. *)
: Iteration limit of 1000 exceeded.
= $Aborted
"""

summary_text = "attribute for associative symbols"
Expand Down
20 changes: 0 additions & 20 deletions mathics/builtin/compilation.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,32 +57,12 @@ class Compile(Builtin):
= CompiledFunction[{x}, Sin[x], -CompiledCode-]
>> cf[1.4]
= 0.98545
#> cf[1/2]
= 0.479426
#> cf[4]
= -0.756802
#> cf[x]
: Invalid argument x should be Integer, Real or boolean.
= CompiledFunction[{x}, Sin[x], -CompiledCode-][x]
#> cf = Compile[{{x, _Real}, {x, _Integer}}, Sin[x + y]]
: Duplicate parameter x found in {{x, _Real}, {x, _Integer}}.
= Compile[{{x, _Real}, {x, _Integer}}, Sin[x + y]]
#> cf = Compile[{{x, _Real}, {y, _Integer}}, Sin[x + z]]
= CompiledFunction[{x, y}, Sin[x + z], -PythonizedCode-]
#> cf = Compile[{{x, _Real}, {y, _Integer}}, Sin[x + y]]
= CompiledFunction[{x, y}, Sin[x + y], -CompiledCode-]
#> cf[1, 2]
= 0.14112
#> cf[x + y]
= CompiledFunction[{x, y}, Sin[x + y], -CompiledCode-][x + y]
Compile supports basic flow control:
>> cf = Compile[{{x, _Real}, {y, _Integer}}, If[x == 0.0 && y <= 0, 0.0, Sin[x ^ y] + 1 / Min[x, 0.5]] + 0.5]
= CompiledFunction[{x, y}, ..., -CompiledCode-]
>> cf[3.5, 2]
= 2.18888
#> cf[0, -2]
= 0.5
Loops and variable assignments are supported usinv Python builtin "compile" function:
>> Compile[{{a, _Integer}, {b, _Integer}}, While[b != 0, {a, b} = {b, Mod[a, b]}]; a] (* GCD of a, b *)
Expand Down
24 changes: 0 additions & 24 deletions mathics/builtin/datentime.py
Original file line number Diff line number Diff line change
Expand Up @@ -375,10 +375,6 @@ class AbsoluteTime(_DateFormat):
>> AbsoluteTime[{"6-6-91", {"Day", "Month", "YearShort"}}]
= 2885155200
## Mathematica Bug - Mathics gets it right
#> AbsoluteTime[1000]
= 1000
"""

summary_text = "get absolute time in seconds"
Expand Down Expand Up @@ -834,10 +830,6 @@ class DateList(_DateFormat):
: The interpretation of 1/10/1991 is ambiguous.
= {1991, 1, 10, 0, 0, 0.}
#> DateList["7/8/9"]
: The interpretation of 7/8/9 is ambiguous.
= {2009, 7, 8, 0, 0, 0.}
>> DateList[{"31/10/91", {"Day", "Month", "YearShort"}}]
= {1991, 10, 31, 0, 0, 0.}
Expand Down Expand Up @@ -912,22 +904,6 @@ class DateString(_DateFormat):
Non-integer values are accepted too:
>> DateString[{1991, 6, 6.5}]
= Thu 6 Jun 1991 12:00:00
## Check Leading 0
#> DateString[{1979, 3, 14}, {"DayName", " ", "MonthShort", "-", "YearShort"}]
= Wednesday 3-79
#> DateString[{"DayName", " ", "Month", "/", "YearShort"}]
= ...
## Assumed separators
#> DateString[{"06/06/1991", {"Month", "Day", "Year"}}]
= Thu 6 Jun 1991 00:00:00
## Specified separators
#> DateString[{"06/06/1991", {"Month", "/", "Day", "/", "Year"}}]
= Thu 6 Jun 1991 00:00:00
"""

attributes = A_READ_PROTECTED | A_PROTECTED
Expand Down
3 changes: 0 additions & 3 deletions mathics/builtin/graphics.py
Original file line number Diff line number Diff line change
Expand Up @@ -1450,9 +1450,6 @@ class Text(Inset):
>> Graphics[{Text["First", {0, 0}], Text["Second", {1, 1}]}, Axes->True, PlotRange->{{-2, 2}, {-2, 2}}]
= -Graphics-
#> Graphics[{Text[x, {0,0}]}]
= -Graphics-
"""

summary_text = "arbitrary text or other expressions in 2D or 3D"
Expand Down
82 changes: 0 additions & 82 deletions mathics/builtin/patterns.py
Original file line number Diff line number Diff line change
Expand Up @@ -327,9 +327,6 @@ class ReplaceAll(BinaryOperator):
>> ReplaceAll[{a -> 1}][{a, b}]
= {1, b}
#> a + b /. x_ + y_ -> {x, y}
= {a, b}
ReplaceAll replaces the shallowest levels first:
>> ReplaceAll[x[1], {x[1] -> y, 1 -> 2}]
= y
Expand Down Expand Up @@ -761,9 +758,6 @@ class Alternatives(BinaryOperator, PatternObject):
Alternatives can also be used for string expressions
>> StringReplace["0123 3210", "1" | "2" -> "X"]
= 0XX3 3XX0
#> StringReplace["h1d9a f483", DigitCharacter | WhitespaceCharacter -> ""]
= hdaf
"""

arg_counts = None
Expand Down Expand Up @@ -829,9 +823,6 @@ class Except(PatternObject):
Except can also be used for string expressions:
>> StringReplace["Hello world!", Except[LetterCharacter] -> ""]
= Helloworld
#> StringReplace["abc DEF 123!", Except[LetterCharacter, WordCharacter] -> "0"]
= abc DEF 000!
"""

arg_counts = [1, 2]
Expand Down Expand Up @@ -1091,15 +1082,6 @@ class Optional(BinaryOperator, PatternObject):
>> Default[h, k_] := k
>> h[a] /. h[x_, y_.] -> {x, y}
= {a, 2}
#> a:b:c
= a : b : c
#> FullForm[a:b:c]
= Optional[Pattern[a, b], c]
#> (a:b):c
= a : b : c
#> a:(b:c)
= a : (b : c)
"""

arg_counts = [1, 2]
Expand Down Expand Up @@ -1235,9 +1217,6 @@ class Blank(_Blank):
'Blank' only matches a single expression:
>> MatchQ[f[1, 2], f[_]]
= False
#> StringReplace["hello world!", _ -> "x"]
= xxxxxxxxxxxx
"""

rules = {
Expand Down Expand Up @@ -1293,14 +1272,6 @@ class BlankSequence(_Blank):
'Sequence' object:
>> f[1, 2, 3] /. f[x__] -> x
= Sequence[1, 2, 3]
#> f[a, b, c, d] /. f[x__, c, y__] -> {{x},{y}}
= {{a, b}, {d}}
#> a + b + c + d /. Plus[x__, c] -> {x}
= {a, b, d}
#> StringReplace[{"ab", "abc", "abcd"}, "b" ~~ __ -> "x"]
= {ab, ax, ax}
"""

rules = {
Expand Down Expand Up @@ -1350,21 +1321,6 @@ class BlankNullSequence(_Blank):
empty sequence:
>> MatchQ[f[], f[___]]
= True
## This test hits infinite recursion
##
##The value captured by a named 'BlankNullSequence' pattern is a
##'Sequence' object, which can have no elements:
##>> f[] /. f[x___] -> x
## = Sequence[]
#> ___symbol
= ___symbol
#> ___symbol //FullForm
= BlankNullSequence[symbol]
#> StringReplace[{"ab", "abc", "abcd"}, "b" ~~ ___ -> "x"]
= {ax, ax, ax}
"""

rules = {
Expand Down Expand Up @@ -1414,16 +1370,6 @@ class Repeated(PostfixOperator, PatternObject):
= {{}, a, {a, b}, a, {a, a, a, a}}
>> f[x, 0, 0, 0] /. f[x, s:0..] -> s
= Sequence[0, 0, 0]
#> 1.. // FullForm
= Repeated[1]
#> 8^^1.. // FullForm (* Mathematica gets this wrong *)
= Repeated[1]
#> StringReplace["010110110001010", "01".. -> "a"]
= a1a100a0
#> StringMatchQ[#, "a" ~~ ("b"..) ~~ "a"] &/@ {"aa", "aba", "abba"}
= {False, True, True}
"""

arg_counts = [1, 2]
Expand Down Expand Up @@ -1502,14 +1448,6 @@ class RepeatedNull(Repeated):
= RepeatedNull[Pattern[a, BlankNullSequence[Integer]]]
>> f[x] /. f[x, 0...] -> t
= t
#> 1... // FullForm
= RepeatedNull[1]
#> 8^^1... // FullForm (* Mathematica gets this wrong *)
= RepeatedNull[1]
#> StringMatchQ[#, "a" ~~ ("b"...) ~~ "a"] &/@ {"aa", "aba", "abba"}
= {True, True, True}
"""

operator = "..."
Expand Down Expand Up @@ -1666,26 +1604,6 @@ class OptionsPattern(PatternObject):
Options might be given in nested lists:
>> f[x, {{{n->4}}}]
= x ^ 4
#> {opt -> b} /. OptionsPattern[{}] -> t
= t
#> Clear[f]
#> Options[f] = {Power -> 2};
#> f[x_, OptionsPattern[f]] := x ^ OptionValue[Power]
#> f[10]
= 100
#> f[10, Power -> 3]
= 1000
#> Clear[f]
#> Options[f] = {Power -> 2};
#> f[x_, OptionsPattern[]] := x ^ OptionValue[Power]
#> f[10]
= 100
#> f[10, Power -> 3]
= 1000
#> Clear[f]
"""

arg_counts = [0, 1]
Expand Down
83 changes: 82 additions & 1 deletion 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
from test.helper import check_evaluation, session

import pytest

Expand Down Expand Up @@ -226,3 +226,84 @@ def test_Attributes_wrong_args(str_expr, arg_count):
f"SetAttributes called with {arg_count} arguments; 2 arguments are expected.",
),
)


@pytest.mark.parametrize(
("str_expr", "msgs", "str_expected", "fail_msg"),
[
("CleanAll[u];CleanAll[v];", None, None, None),
("SetAttributes[{u, v}, Flat];u[x_] := {x};u[]", None, "u[]", None),
("u[a]", None, "{a}", None),
("v[x_] := x;v[]", None, "v[]", None),
("v[a]", None, "a", None),
(
"v[a, b]",
None,
"v[a, b]",
"in Mathematica: Iteration limit of 4096 exceeded.",
),
("CleanAll[u];CleanAll[v];", None, None, None),
],
)
def test_private_doctests_attributes(str_expr, msgs, str_expected, fail_msg):
""" """
check_evaluation(
str_expr,
str_expected,
to_string_expr=True,
to_string_expected=True,
hold_expected=True,
failure_message=fail_msg,
expected_messages=msgs,
)


@pytest.mark.parametrize(
("str_expr", "msgs", "str_expected", "fail_msg"),
[
("CleanAll[u];CleanAll[v];", None, None, None),
(
"SetAttributes[{u, v}, Flat];u[x_] := {x};u[a, b]",
("Iteration limit of 1000 exceeded.",),
"$Aborted",
None,
),
("u[a, b, c]", ("Iteration limit of 1000 exceeded.",), "$Aborted", None),
(
"v[x_] := x;v[a,b,c]",
("Iteration limit of 1000 exceeded.",),
"$Aborted",
"in Mathematica: Iteration limit of 4096 exceeded.",
),
("CleanAll[u];CleanAll[v];", None, None, None),
],
)
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
Loading

0 comments on commit 0cdc458

Please sign in to comment.