diff --git a/src/sage/doctest/forker.py b/src/sage/doctest/forker.py index da051eabe9f..6087abdde2e 100644 --- a/src/sage/doctest/forker.py +++ b/src/sage/doctest/forker.py @@ -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 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 s)'") + else: + return default_timeout + + class SageDocTestRunner(doctest.DocTestRunner): def __init__(self, *args, **kwds): """ @@ -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: @@ -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 diff --git a/src/sage/interacts/test_jupyter.rst b/src/sage/interacts/test_jupyter.rst index de479411598..d25b9e2c2e5 100644 --- a/src/sage/interacts/test_jupyter.rst +++ b/src/sage/interacts/test_jupyter.rst @@ -205,7 +205,7 @@ Test all interacts from the Sage interact library:: 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) ...Interactive function with 7 widgets f: EvalText(value='sin(x)', description='f') g: EvalText(value='cos(x)', description='g') diff --git a/src/sage/interfaces/maxima_abstract.py b/src/sage/interfaces/maxima_abstract.py index 234e9373fca..02bc6f7eaea 100644 --- a/src/sage/interfaces/maxima_abstract.py +++ b/src/sage/interfaces/maxima_abstract.py @@ -304,7 +304,7 @@ def _commands(self, verbose=True): EXAMPLES:: # The output is kind of random - sage: sorted(maxima._commands(verbose=False)) + sage: sorted(maxima._commands(verbose=False)) # long time (limit 40s) [... 'display', ... diff --git a/src/sage/rings/semirings/tropical_mpolynomial.py b/src/sage/rings/semirings/tropical_mpolynomial.py index d5f5a9d2e43..02602bc3f45 100644 --- a/src/sage/rings/semirings/tropical_mpolynomial.py +++ b/src/sage/rings/semirings/tropical_mpolynomial.py @@ -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. = 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)), diff --git a/src/sage/schemes/elliptic_curves/ell_generic.py b/src/sage/schemes/elliptic_curves/ell_generic.py index 5f560c566b9..317159ae520 100644 --- a/src/sage/schemes/elliptic_curves/ell_generic.py +++ b/src/sage/schemes/elliptic_curves/ell_generic.py @@ -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. = GF(p^2) sage: E = EllipticCurve(K, [a + 3, 5 - a]) diff --git a/src/sage/stats/distributions/discrete_gaussian_lattice.py b/src/sage/stats/distributions/discrete_gaussian_lattice.py index 78f21d29fbb..3916dfe18e1 100644 --- a/src/sage/stats/distributions/discrete_gaussian_lattice.py +++ b/src/sage/stats/distributions/discrete_gaussian_lattice.py @@ -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:: diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index dc59841b816..a51df4388b7 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -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