1
# -*- coding: utf-8 -*-
3
# Copyright © 2009-2010 Pierre Raybaut
4
# Licensed under the terms of the MIT License
5
# (see spyderlib/__init__.py for details)
7
"""Shell Interpreter"""
17
from subprocess import Popen, PIPE
18
from code import InteractiveConsole
21
from spyderlib.utils.dochelpers import isdefined
22
from spyderlib.utils import encoding
24
# Force Python to search modules in the current directory first:
25
sys.path.insert(0, '')
28
def guess_filename(filename):
30
if osp.isfile(filename):
32
if not filename.endswith('.py'):
34
for path in [os.getcwdu()]+sys.path:
35
fname = osp.join(path, filename)
38
elif osp.isfile(fname+'.py'):
40
elif osp.isfile(fname+'.pyw'):
44
class Interpreter(InteractiveConsole, threading.Thread):
45
"""Interpreter, executed in a separate thread"""
48
def __init__(self, namespace=None, exitfunc=None,
49
Output=None, WidgetProxy=None, debug=False):
51
namespace: locals send to InteractiveConsole object
52
commands: list of commands executed at startup
54
InteractiveConsole.__init__(self, namespace)
55
threading.Thread.__init__(self)
59
self.exit_flag = False
65
if exitfunc is not None:
66
atexit.register(exitfunc)
68
self.namespace = self.locals
69
self.namespace['__name__'] = '__main__'
70
self.namespace['execfile'] = self.execfile
71
self.namespace['runfile'] = self.runfile
72
self.namespace['raw_input'] = self.raw_input_replacement
73
self.namespace['help'] = self.help_replacement
75
# Capture all interactive input/output
76
self.initial_stdout = sys.stdout
77
self.initial_stderr = sys.stderr
78
self.initial_stdin = sys.stdin
80
# Create communication pipes
82
self.stdin_read = os.fdopen(pr, "r")
83
self.stdin_write = os.fdopen(pw, "w", 0)
84
self.stdout_write = Output()
85
self.stderr_write = Output()
87
self.input_condition = threading.Condition()
88
self.widget_proxy = WidgetProxy(self.input_condition)
93
#------ Standard input/output
94
def redirect_stds(self):
97
sys.stdout = self.stdout_write
98
sys.stderr = self.stderr_write
99
sys.stdin = self.stdin_read
101
def restore_stds(self):
104
sys.stdout = self.initial_stdout
105
sys.stderr = self.initial_stderr
106
sys.stdin = self.initial_stdin
108
def raw_input_replacement(self, prompt=''):
109
"""For raw_input builtin function emulation"""
110
self.widget_proxy.wait_input(prompt)
111
self.input_condition.acquire()
112
while not self.widget_proxy.data_available():
113
self.input_condition.wait()
114
inp = self.widget_proxy.input_data
115
self.input_condition.release()
118
def help_replacement(self, text=None, interactive=False):
119
"""For help builtin function emulation"""
120
if text is not None and not interactive:
121
return pydoc.help(text)
123
pyver = "%d.%d" % (sys.version_info[0], sys.version_info[1])
125
Welcome to Python %s! This is the online help utility.
127
If this is your first time using Python, you should definitely check out
128
the tutorial on the Internet at http://www.python.org/doc/tut/.
130
Enter the name of any module, keyword, or topic to get help on writing
131
Python programs and using Python modules. To quit this help utility and
132
return to the interpreter, just type "quit".
134
To get a list of available modules, keywords, or topics, type "modules",
135
"keywords", or "topics". Each module also comes with a one-line summary
136
of what it does; to list the modules whose summaries contain a given word
137
such as "spam", type "modules spam".
142
eval("pydoc.help(%s)" % text)
143
except (NameError, SyntaxError):
144
print "no Python documentation found for '%r'" % text
145
self.write(os.linesep)
146
self.widget_proxy.new_prompt("help> ")
147
inp = self.raw_input_replacement()
149
self.help_replacement(inp, interactive=True)
152
You are now leaving help and returning to the Python interpreter.
153
If you want to ask for help on a particular object directly from the
154
interpreter, you can type "help(object)". Executing "help('string')"
155
has the same effect as typing a particular string at the help> prompt.
158
def run_command(self, cmd, new_prompt=True):
159
"""Run command in interpreter"""
161
self.exit_flag = True
164
# -- Special commands type I
165
# (transformed into commands executed in the interpreter)
167
special_pattern = r"^%s (?:r\')?(?:u\')?\"?\'?([a-zA-Z0-9_\.]+)"
168
run_match = re.match(special_pattern % 'run', cmd)
169
help_match = re.match(r'^([a-zA-Z0-9_\.]+)\?$', cmd)
170
cd_match = re.match(r"^\!cd \"?\'?([a-zA-Z0-9_ \.]+)", cmd)
172
cmd = 'help(%s)' % help_match.group(1)
175
filename = guess_filename(run_match.groups()[0])
176
cmd = 'runfile(r"%s", args=None)' % filename
179
cmd = 'import os; os.chdir(r"%s")' % cd_match.groups()[0].strip()
180
# -- End of Special commands type I
182
# -- Special commands type II
183
# (don't need code execution in interpreter)
184
xedit_match = re.match(special_pattern % 'xedit', cmd)
185
edit_match = re.match(special_pattern % 'edit', cmd)
186
clear_match = re.match(r"^clear ([a-zA-Z0-9_, ]+)", cmd)
187
# (external) edit command
189
filename = guess_filename(xedit_match.groups()[0])
190
self.widget_proxy.edit(filename, external_editor=True)
193
filename = guess_filename(edit_match.groups()[0])
194
if osp.isfile(filename):
195
self.widget_proxy.edit(filename)
197
self.stderr_write.write(
198
"No such file or directory: %s\n" % filename)
199
# remove reference (equivalent to MATLAB's clear command)
201
varnames = clear_match.groups()[0].replace(' ', '').split(',')
202
for varname in varnames:
204
self.namespace.pop(varname)
208
elif cmd.startswith('!'):
210
pipe = Popen(cmd[1:], shell=True,
211
stdin=PIPE, stderr=PIPE, stdout=PIPE)
212
txt_out = encoding.transcode( pipe.stdout.read() )
213
txt_err = encoding.transcode( pipe.stderr.read().rstrip() )
215
self.stderr_write.write(txt_err)
217
self.stdout_write.write(txt_out)
218
self.stdout_write.write('\n')
220
# -- End of Special commands type II
222
# Command executed in the interpreter
223
# self.widget_proxy.set_readonly(True)
224
self.more = self.push(cmd)
225
# self.widget_proxy.set_readonly(False)
228
self.widget_proxy.new_prompt(self.p2 if self.more else self.p1)
233
"""Wait for input and run it"""
234
while not self.exit_flag:
238
line = self.stdin_read.readline()
241
# Remove last character which is always '\n':
242
self.run_command(line[:-1])
244
def get_thread_id(self):
245
"""Return thread id"""
247
for thread_id, obj in threading._active.items():
252
def raise_keyboard_interrupt(self):
254
ctypes.pythonapi.PyThreadState_SetAsyncExc(self.get_thread_id(),
255
ctypes.py_object(KeyboardInterrupt))
262
"""Actions to be done before restarting this interpreter"""
265
def execfile(self, filename):
267
source = open(filename, 'r').read()
270
name = filename.encode('ascii')
271
except UnicodeEncodeError:
272
name = '<executed_script>'
273
code = compile(source, name, "exec")
274
except (OverflowError, SyntaxError):
275
InteractiveConsole.showsyntaxerror(self, filename)
279
def runfile(self, filename, args=None):
282
args: command line arguments (string)
284
if args is not None and not isinstance(args, basestring):
285
raise TypeError("expected a character buffer object")
286
self.namespace['__file__'] = filename
287
sys.argv = [filename]
289
for arg in args.split():
291
self.execfile(filename)
293
self.namespace.pop('__file__')
295
def eval(self, text):
297
Evaluate text and return (obj, valid)
298
where *obj* is the object represented by *text*
299
and *valid* is True if object evaluation did not raise any exception
301
assert isinstance(text, (str, unicode))
303
return eval(text, self.locals), True
307
def is_defined(self, objtxt, force_import=False):
308
"""Return True if object is defined"""
309
return isdefined(objtxt, force_import=force_import,
310
namespace=self.locals)
312
#===========================================================================
313
# InteractiveConsole API
314
#===========================================================================
315
def push(self, line):
317
Push a line of source text to the interpreter
319
The line should not have a trailing newline; it may have internal
320
newlines. The line is appended to a buffer and the interpreter’s
321
runsource() method is called with the concatenated contents of the
322
buffer as source. If this indicates that the command was executed
323
or invalid, the buffer is reset; otherwise, the command is incomplete,
324
and the buffer is left as it was after the line was appended.
325
The return value is True if more input is required, False if the line
326
was dealt with in some way (this is the same as runsource()).
328
return InteractiveConsole.push(self, line)
330
def resetbuffer(self):
331
"""Remove any unhandled source text from the input buffer"""
332
InteractiveConsole.resetbuffer(self)
1
# -*- coding: utf-8 -*-
3
# Copyright © 2009-2010 Pierre Raybaut
4
# Licensed under the terms of the MIT License
5
# (see spyderlib/__init__.py for details)
7
"""Shell Interpreter"""
17
from subprocess import Popen, PIPE
18
from code import InteractiveConsole
21
from spyderlib.utils.dochelpers import isdefined
22
from spyderlib.utils import encoding
24
# Force Python to search modules in the current directory first:
25
sys.path.insert(0, '')
28
def guess_filename(filename):
30
if osp.isfile(filename):
32
if not filename.endswith('.py'):
34
for path in [os.getcwdu()]+sys.path:
35
fname = osp.join(path, filename)
38
elif osp.isfile(fname+'.py'):
40
elif osp.isfile(fname+'.pyw'):
44
class Interpreter(InteractiveConsole, threading.Thread):
45
"""Interpreter, executed in a separate thread"""
48
def __init__(self, namespace=None, exitfunc=None,
49
Output=None, WidgetProxy=None, debug=False):
51
namespace: locals send to InteractiveConsole object
52
commands: list of commands executed at startup
54
InteractiveConsole.__init__(self, namespace)
55
threading.Thread.__init__(self)
59
self.exit_flag = False
65
if exitfunc is not None:
66
atexit.register(exitfunc)
68
self.namespace = self.locals
69
self.namespace['__name__'] = '__main__'
70
self.namespace['execfile'] = self.execfile
71
self.namespace['runfile'] = self.runfile
72
self.namespace['raw_input'] = self.raw_input_replacement
73
self.namespace['help'] = self.help_replacement
75
# Capture all interactive input/output
76
self.initial_stdout = sys.stdout
77
self.initial_stderr = sys.stderr
78
self.initial_stdin = sys.stdin
80
# Create communication pipes
82
self.stdin_read = os.fdopen(pr, "r")
83
self.stdin_write = os.fdopen(pw, "w", 0)
84
self.stdout_write = Output()
85
self.stderr_write = Output()
87
self.input_condition = threading.Condition()
88
self.widget_proxy = WidgetProxy(self.input_condition)
93
#------ Standard input/output
94
def redirect_stds(self):
97
sys.stdout = self.stdout_write
98
sys.stderr = self.stderr_write
99
sys.stdin = self.stdin_read
101
def restore_stds(self):
104
sys.stdout = self.initial_stdout
105
sys.stderr = self.initial_stderr
106
sys.stdin = self.initial_stdin
108
def raw_input_replacement(self, prompt=''):
109
"""For raw_input builtin function emulation"""
110
self.widget_proxy.wait_input(prompt)
111
self.input_condition.acquire()
112
while not self.widget_proxy.data_available():
113
self.input_condition.wait()
114
inp = self.widget_proxy.input_data
115
self.input_condition.release()
118
def help_replacement(self, text=None, interactive=False):
119
"""For help builtin function emulation"""
120
if text is not None and not interactive:
121
return pydoc.help(text)
123
pyver = "%d.%d" % (sys.version_info[0], sys.version_info[1])
125
Welcome to Python %s! This is the online help utility.
127
If this is your first time using Python, you should definitely check out
128
the tutorial on the Internet at http://www.python.org/doc/tut/.
130
Enter the name of any module, keyword, or topic to get help on writing
131
Python programs and using Python modules. To quit this help utility and
132
return to the interpreter, just type "quit".
134
To get a list of available modules, keywords, or topics, type "modules",
135
"keywords", or "topics". Each module also comes with a one-line summary
136
of what it does; to list the modules whose summaries contain a given word
137
such as "spam", type "modules spam".
142
eval("pydoc.help(%s)" % text)
143
except (NameError, SyntaxError):
144
print "no Python documentation found for '%r'" % text
145
self.write(os.linesep)
146
self.widget_proxy.new_prompt("help> ")
147
inp = self.raw_input_replacement()
149
self.help_replacement(inp, interactive=True)
152
You are now leaving help and returning to the Python interpreter.
153
If you want to ask for help on a particular object directly from the
154
interpreter, you can type "help(object)". Executing "help('string')"
155
has the same effect as typing a particular string at the help> prompt.
158
def run_command(self, cmd, new_prompt=True):
159
"""Run command in interpreter"""
161
self.exit_flag = True
164
# -- Special commands type I
165
# (transformed into commands executed in the interpreter)
167
special_pattern = r"^%s (?:r\')?(?:u\')?\"?\'?([a-zA-Z0-9_\.]+)"
168
run_match = re.match(special_pattern % 'run', cmd)
169
help_match = re.match(r'^([a-zA-Z0-9_\.]+)\?$', cmd)
170
cd_match = re.match(r"^\!cd \"?\'?([a-zA-Z0-9_ \.]+)", cmd)
172
cmd = 'help(%s)' % help_match.group(1)
175
filename = guess_filename(run_match.groups()[0])
176
cmd = 'runfile(r"%s", args=None)' % filename
179
cmd = 'import os; os.chdir(r"%s")' % cd_match.groups()[0].strip()
180
# -- End of Special commands type I
182
# -- Special commands type II
183
# (don't need code execution in interpreter)
184
xedit_match = re.match(special_pattern % 'xedit', cmd)
185
edit_match = re.match(special_pattern % 'edit', cmd)
186
clear_match = re.match(r"^clear ([a-zA-Z0-9_, ]+)", cmd)
187
# (external) edit command
189
filename = guess_filename(xedit_match.groups()[0])
190
self.widget_proxy.edit(filename, external_editor=True)
193
filename = guess_filename(edit_match.groups()[0])
194
if osp.isfile(filename):
195
self.widget_proxy.edit(filename)
197
self.stderr_write.write(
198
"No such file or directory: %s\n" % filename)
199
# remove reference (equivalent to MATLAB's clear command)
201
varnames = clear_match.groups()[0].replace(' ', '').split(',')
202
for varname in varnames:
204
self.namespace.pop(varname)
208
elif cmd.startswith('!'):
210
pipe = Popen(cmd[1:], shell=True,
211
stdin=PIPE, stderr=PIPE, stdout=PIPE)
212
txt_out = encoding.transcode( pipe.stdout.read() )
213
txt_err = encoding.transcode( pipe.stderr.read().rstrip() )
215
self.stderr_write.write(txt_err)
217
self.stdout_write.write(txt_out)
218
self.stdout_write.write('\n')
220
# -- End of Special commands type II
222
# Command executed in the interpreter
223
# self.widget_proxy.set_readonly(True)
224
self.more = self.push(cmd)
225
# self.widget_proxy.set_readonly(False)
228
self.widget_proxy.new_prompt(self.p2 if self.more else self.p1)
233
"""Wait for input and run it"""
234
while not self.exit_flag:
238
line = self.stdin_read.readline()
241
# Remove last character which is always '\n':
242
self.run_command(line[:-1])
244
def get_thread_id(self):
245
"""Return thread id"""
247
for thread_id, obj in threading._active.items():
252
def raise_keyboard_interrupt(self):
254
ctypes.pythonapi.PyThreadState_SetAsyncExc(self.get_thread_id(),
255
ctypes.py_object(KeyboardInterrupt))
262
"""Actions to be done before restarting this interpreter"""
265
def execfile(self, filename):
267
source = open(filename, 'r').read()
270
name = filename.encode('ascii')
271
except UnicodeEncodeError:
272
name = '<executed_script>'
273
code = compile(source, name, "exec")
274
except (OverflowError, SyntaxError):
275
InteractiveConsole.showsyntaxerror(self, filename)
279
def runfile(self, filename, args=None):
282
args: command line arguments (string)
284
if args is not None and not isinstance(args, basestring):
285
raise TypeError("expected a character buffer object")
286
self.namespace['__file__'] = filename
287
sys.argv = [filename]
289
for arg in args.split():
291
self.execfile(filename)
293
self.namespace.pop('__file__')
295
def eval(self, text):
297
Evaluate text and return (obj, valid)
298
where *obj* is the object represented by *text*
299
and *valid* is True if object evaluation did not raise any exception
301
assert isinstance(text, (str, unicode))
303
return eval(text, self.locals), True
307
def is_defined(self, objtxt, force_import=False):
308
"""Return True if object is defined"""
309
return isdefined(objtxt, force_import=force_import,
310
namespace=self.locals)
312
#===========================================================================
313
# InteractiveConsole API
314
#===========================================================================
315
def push(self, line):
317
Push a line of source text to the interpreter
319
The line should not have a trailing newline; it may have internal
320
newlines. The line is appended to a buffer and the interpreter’s
321
runsource() method is called with the concatenated contents of the
322
buffer as source. If this indicates that the command was executed
323
or invalid, the buffer is reset; otherwise, the command is incomplete,
324
and the buffer is left as it was after the line was appended.
325
The return value is True if more input is required, False if the line
326
was dealt with in some way (this is the same as runsource()).
328
return InteractiveConsole.push(self, "#coding=utf-8\n" + line)
330
def resetbuffer(self):
331
"""Remove any unhandled source text from the input buffer"""
332
InteractiveConsole.resetbuffer(self)
b'\\ No newline at end of file'