3939 SymbolInfinity ,
4040 SymbolRowBox ,
4141)
42- from mathics .eval .datetime import eval_timeconstrained , valid_time_from_expression
4342from 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+
4549START_TIME = time .time ()
4650
4751TIME_INCREMENTS = {
@@ -1094,35 +1098,34 @@ def evaluate(self, evaluation: Evaluation) -> Expression:
10941098
10951099
10961100class 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
11611170class TimeZone (Predefined ):
0 commit comments