Skip to content

Commit adb62c0

Browse files
author
Release Manager
committed
gh-35882: avoid messing with the recursion limit Fixes #35803. URL: #35882 Reported by: Marc Mezzarobba Reviewer(s): Frédéric Chapoton
2 parents a1a27b1 + 874119d commit adb62c0

File tree

5 files changed

+76
-44
lines changed

5 files changed

+76
-44
lines changed

src/sage/functions/transcendental.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
# ****************************************************************************
1818
import sys
1919

20+
from sage.misc.misc import increase_recursion_limit
2021
from sage.rings.integer_ring import ZZ
2122
from sage.rings.real_mpfr import RR
2223
from sage.rings.real_double import RDF
@@ -551,9 +552,8 @@ def _eval_(self, x):
551552
max = x.parent()(1.1)*x + 10
552553
abs_prec = (-self.approximate(max).log2() + rel_prec + 2*max.log2()).ceil()
553554
self._f = {}
554-
if sys.getrecursionlimit() < max + 10:
555-
sys.setrecursionlimit(int(max) + 10)
556-
self._compute_power_series(max.floor(), abs_prec, cache_ring=x.parent())
555+
with increase_recursion_limit(int(max)):
556+
self._compute_power_series(max.floor(), abs_prec, cache_ring=x.parent())
557557
return self._f[n](2*(x-n-x.parent()(0.5)))
558558

559559
def power_series(self, n, abs_prec):

src/sage/interfaces/sympy.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1016,7 +1016,7 @@ def _sympysage_true(self):
10161016

10171017

10181018
#------------------------------------------------------------------
1019-
from sage.repl.ipython_extension import run_once
1019+
from sage.misc.misc import run_once
10201020

10211021
@run_once
10221022
def sympy_init():

src/sage/misc/misc.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,11 @@
3838
# https://www.gnu.org/licenses/
3939
# ****************************************************************************
4040

41+
import contextlib
42+
import functools
4143
import os
4244
import pdb
45+
import sys
4346
import warnings
4447

4548
from .lazy_string import lazy_string
@@ -1132,3 +1135,68 @@ def inject_variable_test(name, value, depth):
11321135
inject_variable(name, value)
11331136
else:
11341137
inject_variable_test(name, value, depth - 1)
1138+
1139+
1140+
# from https://stackoverflow.com/questions/4103773/efficient-way-of-having-a-function-only-execute-once-in-a-loop
1141+
def run_once(func):
1142+
"""
1143+
Runs a function (successfully) only once.
1144+
1145+
The running can be reset by setting the ``has_run`` attribute to False
1146+
1147+
TESTS::
1148+
1149+
sage: from sage.repl.ipython_extension import run_once
1150+
sage: @run_once
1151+
....: def foo(work):
1152+
....: if work:
1153+
....: return 'foo worked'
1154+
....: raise RuntimeError("foo didn't work")
1155+
sage: foo(False)
1156+
Traceback (most recent call last):
1157+
...
1158+
RuntimeError: foo didn't work
1159+
sage: foo(True)
1160+
'foo worked'
1161+
sage: foo(False)
1162+
sage: foo(True)
1163+
"""
1164+
@functools.wraps(func)
1165+
def wrapper(*args, **kwargs):
1166+
if not wrapper.has_run:
1167+
result = func(*args, **kwargs)
1168+
wrapper.has_run = True
1169+
return result
1170+
wrapper.has_run = False
1171+
return wrapper
1172+
1173+
1174+
@contextlib.contextmanager
1175+
def increase_recursion_limit(increment):
1176+
r"""
1177+
Context manager to temporarily change the Python maximum recursion depth.
1178+
1179+
INPUT:
1180+
1181+
- `increment`: increment to add to the current limit
1182+
1183+
EXAMPLES::
1184+
1185+
sage: from sage.misc.misc import increase_recursion_limit
1186+
sage: def rec(n): None if n == 0 else rec(n-1)
1187+
sage: rec(10000)
1188+
Traceback (most recent call last):
1189+
...
1190+
RecursionError: maximum recursion depth exceeded...
1191+
sage: with increase_recursion_limit(10000): rec(10000)
1192+
sage: rec(10000)
1193+
Traceback (most recent call last):
1194+
...
1195+
RecursionError: maximum recursion depth exceeded...
1196+
"""
1197+
old_limit = sys.getrecursionlimit()
1198+
sys.setrecursionlimit(old_limit + increment)
1199+
try:
1200+
yield
1201+
finally:
1202+
sys.setrecursionlimit(old_limit)

src/sage/repl/ipython_extension.py

Lines changed: 1 addition & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
from sage.repl.load import load_wrap
6969
from sage.env import SAGE_IMPORTALL, SAGE_STARTUP_FILE
7070
from sage.misc.lazy_import import LazyImport
71+
from sage.misc.misc import run_once
7172

7273
@magics_class
7374
class SageMagics(Magics):
@@ -583,41 +584,6 @@ def all_globals():
583584
return all_jupyter
584585

585586

586-
# from https://stackoverflow.com/questions/4103773/efficient-way-of-having-a-function-only-execute-once-in-a-loop
587-
from functools import wraps
588-
def run_once(func):
589-
"""
590-
Runs a function (successfully) only once.
591-
592-
The running can be reset by setting the ``has_run`` attribute to False
593-
594-
TESTS::
595-
596-
sage: from sage.repl.ipython_extension import run_once
597-
sage: @run_once
598-
....: def foo(work):
599-
....: if work:
600-
....: return 'foo worked'
601-
....: raise RuntimeError("foo didn't work")
602-
sage: foo(False)
603-
Traceback (most recent call last):
604-
...
605-
RuntimeError: foo didn't work
606-
sage: foo(True)
607-
'foo worked'
608-
sage: foo(False)
609-
sage: foo(True)
610-
"""
611-
@wraps(func)
612-
def wrapper(*args, **kwargs):
613-
if not wrapper.has_run:
614-
result = func(*args, **kwargs)
615-
wrapper.has_run = True
616-
return result
617-
wrapper.has_run = False
618-
return wrapper
619-
620-
621587
@run_once
622588
def load_ipython_extension(ip):
623589
"""

src/sage/rings/qqbar.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,7 @@
560560
from sage.misc.fast_methods import Singleton
561561
from sage.misc.cachefunc import cached_method
562562
from sage.misc.lazy_string import lazy_string
563+
from sage.misc.misc import increase_recursion_limit
563564
from sage.structure.coerce import parent_is_numerical, parent_is_real_numerical
564565
from sage.structure.sage_object import SageObject
565566
from sage.structure.richcmp import (richcmp, richcmp_method,
@@ -8543,9 +8544,7 @@ def exactify(self):
85438544
sage: sys.setrecursionlimit(old_recursion_limit)
85448545
"""
85458546
import sys
8546-
old_recursion_limit = sys.getrecursionlimit()
8547-
sys.setrecursionlimit(old_recursion_limit + 10)
8548-
try:
8547+
with increase_recursion_limit(10):
85498548
left = self._left
85508549
right = self._right
85518550
left.exactify()
@@ -8560,8 +8559,7 @@ def exactify(self):
85608559
return ANRational(value)
85618560
else:
85628561
return ANExtensionElement(gen, value)
8563-
finally:
8564-
sys.setrecursionlimit(old_recursion_limit)
8562+
85658563

85668564
# These are the functions used to add, subtract, multiply, and divide
85678565
# algebraic numbers. Basically, we try to compute exactly if both

0 commit comments

Comments
 (0)