Skip to content

Commit 54e48ae

Browse files
mmaterarocky
authored andcommitted
using patched stopit for the TimeConstrained support
1 parent 73cbe0a commit 54e48ae

File tree

6 files changed

+69
-34
lines changed

6 files changed

+69
-34
lines changed

.github/workflows/macos.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,13 @@ jobs:
3333
cd stopit/
3434
pip install -e .
3535
cd ..
36+
python -m pip install -e git+https://github.com/Mathics3/mathics-scanner#egg=Mathics-Scanner[full]
37+
# We can comment out after next Mathics-Scanner release
38+
git clone --depth 1 https://github.com/Mathics3/mathics-scanner.git
39+
# git clone --single-branch --branch operator-refactor-part1.5 https://github.com/Mathics3/mathics-scanner.git
40+
cd mathics-scanner/
41+
pip install -e .
42+
cd ..
3643
# We can comment out after next Mathics-Scanner release
3744
# python -m pip install Mathics-Scanner[full]
3845
# python -m pip install -e git+https://github.com/Mathics3/mathics-scanner#egg=Mathics-Scanner[full]

.github/workflows/pyodide.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ jobs:
5454
5555
pip install "setuptools>=70.0.0" PyYAML click packaging pytest
5656
57+
# First install our patched version of stopit
58+
git clone --depth 1 https://github.com/Mathics3/stopit.git
59+
cd stopit/
60+
pip install -e .
61+
cd ..
5762
# We can comment out after next Mathics-Scanner release
5863
# python -m pip install --no-build-isolation -e git+https://github.com/Mathics3/mathics-scanner#egg=Mathics-Scanner
5964
# pip install --no-build-isolation -e .

.github/workflows/ubuntu.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ jobs:
3030
pip install -e .
3131
cd ..
3232
# We can comment out after next Mathics-Scanner release
33+
# python -m pip install -e git+https://github.com/Mathics3/mathics-scanner#egg=Mathics-Scanner[full]
34+
git clone --depth 1 https://github.com/Mathics3/mathics-scanner.git
35+
# git clone --single-branch --branch operator-refactor-part1.5 https://github.com/Mathics3/mathics-scanner.git
36+
cd mathics-scanner/
37+
pip install -e .
38+
cd ..
39+
# We can comment out after next Mathics-Scanner release
3340
# python -m pip install Mathics-Scanner[full]
3441
# python -m pip install -e git+https://github.com/Mathics3/mathics-scanner#egg=Mathics-Scanner[full]
3542
pip install -e .

.github/workflows/windows.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@ jobs:
3939
pip install -e .
4040
cd ..
4141
# We can comment out after next Mathics-Scanner release
42+
python -m pip install -e git+https://github.com/Mathics3/mathics-scanner#egg=Mathics-Scanner[full]
43+
git clone --depth 1 https://github.com/Mathics3/mathics-scanner.git
44+
# git clone --single-branch --branch operator-refactor-part1.5 https://github.com/Mathics3/mathics-scanner.git
45+
cd mathics-scanner
46+
pip install -e .
47+
cd ..
48+
# We can comment out after next Mathics-Scanner release
4249
# python -m pip install -e git+https://github.com/Mathics3/mathics-scanner#egg=Mathics-Scanner[full]
4350
pip install -e .
4451

mathics/builtin/datentime.py

Lines changed: 42 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,13 @@
3939
SymbolInfinity,
4040
SymbolRowBox,
4141
)
42-
from mathics.eval.datetime import eval_timeconstrained, valid_time_from_expression
4342
from mathics.settings import TIME_12HOUR
4443

44+
if sys.platform == "emscripten":
45+
from stopit import SignalTimeout as TimeoutHandler
46+
else:
47+
from timed_threads import ThreadingTimeout as TimeoutHandler
48+
4549
START_TIME = time.time()
4650

4751
TIME_INCREMENTS = {
@@ -1094,35 +1098,34 @@ def evaluate(self, evaluation: Evaluation) -> Expression:
10941098

10951099

10961100
class TimeConstrained(Builtin):
1097-
r"""
1101+
"""
10981102
<url>:WMA link:https://reference.wolfram.com/language/ref/TimeConstrained.html</url>
10991103
11001104
<dl>
1101-
<dt>'TimeConstrained'[$expr$, $t$]
1105+
<dt>'TimeConstrained[$expr$, $t$]'
11021106
<dd>'evaluates $expr$, stopping after $t$ seconds.'
11031107
1104-
<dt>'TimeConstrained'[$expr$, $t$, $failexpr$]
1108+
<dt>'TimeConstrained[$expr$, $t$, $failexpr$]'
11051109
<dd>'returns $failexpr$ if the time constraint is not met.'
11061110
</dl>
11071111
11081112
Possible issues: for certain time-consuming functions (like simplify)
11091113
which are based on sympy or other libraries, it is possible that
11101114
the evaluation continues after the timeout. However, at the end of the \
1111-
evaluation, the function will return '\$Aborted' and the results will not affect
1115+
evaluation, the function will return '$Aborted' and the results will not affect
11121116
the state of the Mathics3 kernel.
11131117
1114-
1115-
## >> TimeConstrained[Pause[5]; a, 1]
1116-
## = $Aborted
1117-
1118-
## 'TimeConstrained' can be nested. In this case, the outer 'TimeConstrained' waits for \
1119-
## 2 seconds that the inner sequence be executed. Inner expressions would take in \
1120-
## sequence more than 3 seconds:
1121-
## >> TimeConstrained[TimeConstrained[Pause[1]; Print["First Done"], 2];\
1122-
## TimeConstrained[Pause[5];Print["Second Done"],2,"inner"], \
1123-
## 2, "outer"]
1124-
## | First Done
1125-
## = outer
1118+
>> TimeConstrained[Pause[5]; a, 1]
1119+
= $Aborted
1120+
1121+
'TimeConstrained' can be nested. In this case, the outer 'TimeConstrained' waits for \
1122+
2 seconds that the inner sequence be executed. Inner expressions would take in \
1123+
sequence more than 3 seconds:
1124+
>> TimeConstrained[TimeConstrained[Pause[1]; Print["First Done"], 2];\
1125+
TimeConstrained[Pause[5];Print["Second Done"],2,"inner"], \
1126+
2, "outer"]
1127+
| First Done
1128+
= outer
11261129
"""
11271130

11281131
attributes = A_HOLD_ALL | A_PROTECTED
@@ -1132,30 +1135,36 @@ class TimeConstrained(Builtin):
11321135
"or Infinity."
11331136
),
11341137
}
1135-
if sys.platform == "emscripten":
1136-
messages.update({"tcns": f"TimeConstrained is not supported in {sys.platform}"})
11371138

11381139
summary_text = "run a command for at most a specified time"
11391140

1140-
def eval_with_timeout(self, expr, t, evaluation) -> Optional[BaseElement]:
1141+
def eval_2(self, expr, t, evaluation):
11411142
"TimeConstrained[expr_, t_]"
1142-
try:
1143-
timeout = valid_time_from_expression(t, evaluation)
1144-
except ValueError:
1145-
evaluation.message("TimeConstrained", "timc", t)
1146-
return
1147-
return eval_timeconstrained(expr, timeout, SymbolAborted, evaluation)
1143+
return self.eval_3(expr, t, SymbolAborted, evaluation)
11481144

1149-
def eval_with_timeout_and_failexpr(
1150-
self, expr, t, failexpr, evaluation
1151-
) -> Optional[BaseElement]:
1145+
def eval_3(self, expr, t, failexpr, evaluation):
11521146
"TimeConstrained[expr_, t_, failexpr_]"
1153-
try:
1154-
timeout = valid_time_from_expression(t, evaluation)
1155-
except ValueError:
1147+
t = t.evaluate(evaluation)
1148+
if not t.is_numeric(evaluation):
11561149
evaluation.message("TimeConstrained", "timc", t)
11571150
return
1158-
return eval_timeconstrained(expr, timeout, failexpr, evaluation)
1151+
try:
1152+
timeout = float(t.to_python())
1153+
evaluation.timeout_queue.append((timeout, datetime.now().timestamp()))
1154+
request = lambda: expr.evaluate(evaluation)
1155+
done = False
1156+
with TimeoutHandler(timeout) as to_ctx_mgr:
1157+
assert to_ctx_mgr.state == to_ctx_mgr.EXECUTING
1158+
result = request()
1159+
done = True
1160+
if done:
1161+
evaluation.timeout_queue.pop()
1162+
return result
1163+
except Exception:
1164+
evaluation.timeout_queue.pop()
1165+
raise
1166+
evaluation.timeout_queue.pop()
1167+
return failexpr.evaluate(evaluation)
11591168

11601169

11611170
class TimeZone(Predefined):

0 commit comments

Comments
 (0)