Skip to content

Implement specified timeout for slow doctests #39746

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

Open
wants to merge 15 commits into
base: develop
Choose a base branch
from
Open
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
54 changes: 52 additions & 2 deletions src/sage/doctest/forker.py
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,54 @@ def getvalue(self):
TestResults = namedtuple('TestResults', 'failed attempted')


def _parse_example_timeout(source: str, default_timeout: float) -> float:
"""
Parse the timeout value from a doctest example's source.

INPUT:

- ``source`` -- the source code of a ``doctest.Example``
- ``default_timeout`` -- the default timeout value to use

OUTPUT:

- a float, the timeout value to use for the example

TESTS::

sage: from sage.doctest.forker import _parse_example_timeout
sage: _parse_example_timeout("sleep(10) # long time (limit 10s)", 5.0r)
10.0
sage: _parse_example_timeout("sleep(10) # long time (limit 10s, possible regression)", 5.0r)
10.0
sage: _parse_example_timeout("sleep(10) # long time (20s)", 5.0r)
5.0
sage: _parse_example_timeout("sleep(10) # long time (limit 1a2s)", 5.0r)
Traceback (most recent call last):
...
ValueError: malformed optional tag '# long time (limit 1a2s)', should be '# long time (limit <number>s)'
sage: _parse_example_timeout("sleep(10) # long time (:issue:`12345`)", 5.0r)
5.0
"""
# TODO this double-parsing is inefficient, should make :meth:`SageDocTestParser.parse`
# return subclass of doctest.Example that already include the timeout value
from sage.doctest.parsing import parse_optional_tags
value = parse_optional_tags(source).get("long time", None)
if value is None:
# either has the "long time" tag without any value in parentheses,
# or tag not present
return default_timeout
assert isinstance(value, str)
match = re.fullmatch(r'\s*limit\s+(\S+)s(\s*,.*)?', value.strip())
if match:
try:
return float(match[1])
except ValueError:
raise ValueError(f"malformed optional tag '# long time ({value})', should be '# long time (limit <number>s)'")
else:
return default_timeout


class SageDocTestRunner(doctest.DocTestRunner):
def __init__(self, *args, **kwds):
"""
Expand Down Expand Up @@ -820,8 +868,10 @@ def compiler(example):
if example.warnings:
for warning in example.warnings:
out(self._failure_header(test, example, f'Warning: {warning}'))

if outcome is SUCCESS:
if self.options.warn_long > 0 and example.cputime + check_timer.cputime > self.options.warn_long:
if self.options.warn_long > 0 and example.cputime + check_timer.cputime > _parse_example_timeout(
example.source, self.options.warn_long):
self.report_overtime(out, test, example, got,
check_timer=check_timer)
elif example.warnings:
Expand Down Expand Up @@ -2157,7 +2207,7 @@ def dispatch(self):
sage: DC.reporter = DR
sage: DC.dispatcher = DD
sage: DC.timer = Timer().start()
sage: DD.dispatch()
sage: DD.dispatch() # long time (limit 20s)
sage -t .../sage/modules/free_module_homspace.py
[... tests, ...s wall]
sage -t .../sage/rings/big_oh.py
Expand Down
2 changes: 1 addition & 1 deletion src/sage/interacts/test_jupyter.rst
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@
Exact value of the integral \(\displaystyle\int_{0}^{2}x^{2} +
1\,\mathrm{d}x=4.666666666666668\)

sage: test(interacts.calculus.function_tool) # long time
sage: test(interacts.calculus.function_tool)

Check warning on line 208 in src/sage/interacts/test_jupyter.rst

View workflow job for this annotation

GitHub Actions / Conda (ubuntu, Python 3.11, all)

Warning: slow doctest:

slow doctest:: Test ran for 5.42s cpu, 7.70s wall Check ran for 0.00s cpu, 0.00s wall

Check warning on line 208 in src/sage/interacts/test_jupyter.rst

View workflow job for this annotation

GitHub Actions / Conda (ubuntu, Python 3.12, all, editable)

Warning: slow doctest:

slow doctest:: Test ran for 5.01s cpu, 6.16s wall Check ran for 0.00s cpu, 0.00s wall

Check warning on line 208 in src/sage/interacts/test_jupyter.rst

View workflow job for this annotation

GitHub Actions / Conda (ubuntu, Python 3.12, all)

Warning: slow doctest:

slow doctest:: Test ran for 5.47s cpu, 6.87s wall Check ran for 0.00s cpu, 0.00s wall
...Interactive function <function function_tool at ...> with 7 widgets
f: EvalText(value='sin(x)', description='f')
g: EvalText(value='cos(x)', description='g')
Expand Down
2 changes: 1 addition & 1 deletion src/sage/interfaces/maxima_abstract.py
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@
EXAMPLES::

# The output is kind of random
sage: sorted(maxima._commands(verbose=False))
sage: sorted(maxima._commands(verbose=False)) # long time (limit 40s)
[...
'display',
...
Expand Down Expand Up @@ -337,7 +337,7 @@

EXAMPLES::

sage: t = maxima._tab_completion(verbose=False)

Check warning on line 340 in src/sage/interfaces/maxima_abstract.py

View workflow job for this annotation

GitHub Actions / Conda (ubuntu, Python 3.11, all)

Warning: slow doctest:

slow doctest:: Test ran for 18.39s cpu, 18.36s wall Check ran for 0.00s cpu, 0.00s wall

Check warning on line 340 in src/sage/interfaces/maxima_abstract.py

View workflow job for this annotation

GitHub Actions / Conda (ubuntu, Python 3.12, all, editable)

Warning: slow doctest:

slow doctest:: Test ran for 19.73s cpu, 19.65s wall Check ran for 0.00s cpu, 0.00s wall

Check warning on line 340 in src/sage/interfaces/maxima_abstract.py

View workflow job for this annotation

GitHub Actions / Conda (ubuntu, Python 3.12, all)

Warning: slow doctest:

slow doctest:: Test ran for 19.26s cpu, 19.28s wall Check ran for 0.00s cpu, 0.00s wall

Check warning on line 340 in src/sage/interfaces/maxima_abstract.py

View workflow job for this annotation

GitHub Actions / Conda (macos, Python 3.11, all)

Warning: slow doctest:

slow doctest:: Test ran for 16.64s cpu, 17.06s wall Check ran for 0.00s cpu, 0.00s wall

Check warning on line 340 in src/sage/interfaces/maxima_abstract.py

View workflow job for this annotation

GitHub Actions / Conda (macos, Python 3.12, all)

Warning: slow doctest:

slow doctest:: Test ran for 16.54s cpu, 17.55s wall Check ran for 0.00s cpu, 0.00s wall
sage: 'gcd' in t
True
sage: len(t) # random output
Expand Down
3 changes: 2 additions & 1 deletion src/sage/rings/semirings/tropical_mpolynomial.py
Original file line number Diff line number Diff line change
Expand Up @@ -543,12 +543,13 @@ def dual_subdivision(self):

A subdivision with many faces, not all of which are triangles::

sage: # long time
sage: T = TropicalSemiring(QQ)
sage: R.<x,y> = PolynomialRing(T)
sage: p3 = (R(8) + R(4)*x + R(2)*y + R(1)*x^2 + x*y + R(1)*y^2
....: + R(2)*x^3 + x^2*y + x*y^2 + R(4)*y^3 + R(8)*x^4
....: + R(4)*x^3*y + x^2*y^2 + R(2)*x*y^3 + y^4)
sage: pc = p3.dual_subdivision(); pc
sage: pc = p3.dual_subdivision(); pc # long time (limit 40s)
Polyhedral complex with 10 maximal cells
sage: [p.Vrepresentation() for p in pc.maximal_cells_sorted()]
[(A vertex at (0, 0), A vertex at (0, 1), A vertex at (1, 0)),
Expand Down
2 changes: 2 additions & 0 deletions src/sage/schemes/elliptic_curves/ell_generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -2476,6 +2476,8 @@ def multiplication_by_m(self, m, x_only=False):
sage: assert(E(eval(f,P)) == 2*P)

The following test shows that :issue:`6413` is fixed for elliptic curves over finite fields::

sage: # long time
sage: p = 7
sage: K.<a> = GF(p^2)
sage: E = EllipticCurve(K, [a + 3, 5 - a])
Expand Down
2 changes: 1 addition & 1 deletion src/sage/stats/distributions/discrete_gaussian_lattice.py
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,7 @@ def __init__(self, B, sigma=1, c=0, r=None, precision=None, sigma_basis=False):
....: add_samples(1000)
sage: sum(counter.values()) # random
3000
sage: while abs(m*f(v)*1.0/nf/counter[v] - 1.0) >= 0.1: # needs sage.symbolic
sage: while abs(m*f(v)*1.0/nf/counter[v] - 1.0) >= 0.1: # needs sage.symbolic # long time (limit 20s)
....: add_samples(1000)

If the covariance provided is not positive definite, an error is thrown::
Expand Down
2 changes: 1 addition & 1 deletion src/sage/symbolic/expression.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -13221,7 +13221,7 @@ cdef class Expression(Expression_abc):
answer::

sage: f = ln(1+4/5*sin(x))
sage: integrate(f, x, -3.1415, 3.1415) # random
sage: integrate(f, x, -3.1415, 3.1415) # random # long time (limit 10s)
integrate(log(4/5*sin(x) + 1), x, -3.14150000000000,
3.14150000000000)
sage: # needs sage.libs.giac
Expand Down
Loading