forked from has2k1/gnuplot_kernel
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathreplwrap.py
More file actions
121 lines (98 loc) · 3.23 KB
/
replwrap.py
File metadata and controls
121 lines (98 loc) · 3.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import re
import textwrap
import signal
from metakernel import REPLWrapper
from metakernel.pexpect import TIMEOUT
from .exceptions import GnuplotError
CRLF = '\r\n'
ERROR_REs = [re.compile(r'^\s*\^\s*\n')]
class GnuplotREPLWrapper(REPLWrapper):
# The prompt after the commands run
prompt = ''
def exit(self):
"""
Exit the gnuplot process
"""
try:
self._force_prompt(timeout=.01)
except GnuplotError:
return self.child.kill(signal.SIGKILL)
self.sendline('exit')
def is_error_output(self, text):
"""
Return True if text is recognised as error text
"""
for pattern in ERROR_REs:
if pattern.match(text):
return True
return False
def validate_input(self, code):
"""
Deal with problematic input
Raises GnuplotError if it cannot deal with it.
"""
if code.endswith('\\'):
raise GnuplotError("Do not execute code that "
"endswith backslash.")
# Do not get stuck in the gnuplot process
code = code.replace('\\\n', ' ')
return code
def send(self, cmd):
self.child.send(cmd + '\r')
def _force_prompt(self, timeout=30, n=4):
"""
Force prompt
"""
quick_timeout = .05
if timeout < quick_timeout:
quick_timeout = timeout
def quick_prompt():
try:
self._expect_prompt(timeout=quick_timeout)
return True
except TIMEOUT:
return False
def patient_prompt():
try:
self._expect_prompt(timeout=timeout)
return True
except TIMEOUT:
return False
# Eagerly try to get a prompt quickly,
# If that fails wait a while
for i in range(n):
if quick_prompt():
break
# Probably stuck in help output
if self.child.before:
self.send(self.child.linesep)
else:
# Probably long computation going on
if not patient_prompt():
msg = ("gnuplot prompt failed to return in "
"in {} seconds").format(timeout)
raise GnuplotError(msg)
def run_command(self, code, timeout=-1, stream_handler=None,
stdin_handler=None):
"""
Run code
This overrides the baseclass method to allow for
input validation and error handling.
"""
code = self.validate_input(code)
# Split up multiline commands and feed them in bit-by-bit
stmts = code.splitlines()
output = []
for line in stmts:
self.send(line)
self._force_prompt()
# Removing any crlfs makes subsequent
# processing cleaner
retval = self.child.before.replace(CRLF, '\n')
self.prompt = self.child.after
if self.is_error_output(retval):
msg = '{}\n{}'.format(
line, textwrap.dedent(retval))
raise GnuplotError(msg)
output.append(retval)
return ''.join(output)