Skip to content

Commit

Permalink
Fix interrupting Singular
Browse files Browse the repository at this point in the history
  • Loading branch information
jdemeyer committed Jun 23, 2015
1 parent 45969a6 commit 17d23e9
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 24 deletions.
9 changes: 7 additions & 2 deletions src/sage/interfaces/expect.py
Expand Up @@ -822,10 +822,15 @@ def _eval_line(self, line, allow_use_file=True, wait_for_prompt=True, restart_if
sage: singular._eval_using_file_cutoff = 4
sage: singular._eval_line('for(int i=1;i<=3;i++){i=1;};', wait_for_prompt=False)
''
sage: singular.interrupt(timeout=3) # sometimes very slow (up to 60s on sage.math, 2012)
False
sage: singular.interrupt()
True
sage: singular._eval_using_file_cutoff = cutoff
The interface still works after this interrupt::
sage: singular('2+3')
5
Last, we demonstrate that by default the execution of a command
is tried twice if it fails the first time due to a crashed
interface::
Expand Down
36 changes: 36 additions & 0 deletions src/sage/interfaces/sagespawn.pyx
Expand Up @@ -109,6 +109,42 @@ class SageSpawn(spawn):
"""
Py_INCREF(self)

def expect_peek(self, *args, **kwds):
"""
Like :meth:`expect` but restore the read buffer such that it
looks like nothing was actually read. The next reading will
continue at the current position.
EXAMPLES::
sage: from sage.interfaces.sagespawn import SageSpawn
sage: E = SageSpawn("sh", ["-c", "echo hello world"])
sage: _ = E.expect_peek("w")
sage: E.read()
'hello world\r\n'
"""
ret = self.expect(*args, **kwds)
self.buffer = self.before + self.after + self.buffer
return ret

def expect_upto(self, *args, **kwds):
"""
Like :meth:`expect` but restore the read buffer starting from
the matched string. The next reading will continue starting
with the matched string.
EXAMPLES::
sage: from sage.interfaces.sagespawn import SageSpawn
sage: E = SageSpawn("sh", ["-c", "echo hello world"])
sage: _ = E.expect_upto("w")
sage: E.read()
'world\r\n'
"""
ret = self.expect(*args, **kwds)
self.buffer = self.after + self.buffer
return ret

def close(self):
"""
Quit the child process: send the quit string, close the
Expand Down
68 changes: 46 additions & 22 deletions src/sage/interfaces/singular.py
Expand Up @@ -304,37 +304,22 @@
''
"""



#We could also do these calculations without using the singular
#interface (behind the scenes the interface is used by Sage):
# sage: x, y = PolynomialRing(RationalField(), 2, names=['x','y']).gens()
# sage: C = ProjectivePlaneCurve(y**9 - x**2*(x-1)**9)
# sage: C.genus()
# 0
# sage: C = ProjectivePlaneCurve(y**9 - x**2*(x-1)**9 + x)
# sage: C.genus()
# 40

#*****************************************************************************
# Copyright (C) 2005 David Joyner and William Stein
#
# Distributed under the terms of the GNU General Public License (GPL)
#
# This code is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# The full text of the GPL is available at:
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
# http://www.gnu.org/licenses/
#*****************************************************************************


import os
import re
import sys
import pexpect
from time import sleep

from expect import Expect, ExpectElement, FunctionElement, ExpectFunction

Expand Down Expand Up @@ -386,7 +371,9 @@ def __init__(self, maxread=1000, script_subdirectory=None,
terminal_echo=False,
name = 'singular',
prompt = prompt,
command = "Singular -t --ticks-per-sec 1000", #no tty and fine grained cputime()
# no tty, fine grained cputime()
# and do not display CTRL-C prompt
command = "Singular -t --ticks-per-sec 1000 --cntrlc=a",
maxread = maxread,
server = server,
server_tmpdir = server_tmpdir,
Expand Down Expand Up @@ -468,6 +455,43 @@ def _quit_string(self):
"""
return 'quit'

def _send_interrupt(self):
"""
Send an interrupt to Singular. If needed, additional
semi-colons are sent until we get back at the prompt.
TESTS:
The following works without restarting Singular::
sage: a = singular(1)
sage: _ = singular._expect.sendline('1+') # unfinished input
sage: try:
....: alarm(0.5)
....: singular._expect_expr('>') # interrupt this
....: except KeyboardInterrupt:
....: pass
Control-C pressed. Interrupting Singular. Please wait a few seconds...
We can still access a::
sage: 2*a
2
"""
# Work around for Singular bug
# http://www.singular.uni-kl.de:8002/trac/ticket/727
sleep(0.1)

E = self._expect
E.sendline(chr(3))
for i in range(5):
try:
E.expect_upto(self._prompt, timeout=1.0)
return
except Exception:
pass
E.sendline(";")

def _read_in_file_command(self, filename):
r"""
EXAMPLES::
Expand Down

0 comments on commit 17d23e9

Please sign in to comment.