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
"""Internal shell widget : PythonShellWidget + Interpreter"""
9
# pylint: disable=C0103
10
# pylint: disable=R0903
11
# pylint: disable=R0911
12
# pylint: disable=R0201
14
#FIXME: Internal shell MT: for i in range(100000): print i -> bug
18
from spyderlib.widgets.objecteditor import oedit
19
__builtin__.oedit = oedit
24
from subprocess import Popen
26
from spyderlib.qt.QtGui import QMessageBox
27
from spyderlib.qt.QtCore import SIGNAL, QObject, QEventLoop
30
from spyderlib import get_versions
31
from spyderlib.utils.qthelpers import create_action, get_std_icon
32
from spyderlib.interpreter import Interpreter
33
from spyderlib.utils.dochelpers import getargtxt, getsource, getdoc, getobjdir
34
from spyderlib.utils.misc import get_error_match
35
#TODO: remove the CONF object and make it work anyway
36
# In fact, this 'CONF' object has nothing to do in package spyderlib.widgets
37
# which should not contain anything directly related to Spyder's main app
38
from spyderlib.baseconfig import get_conf_path, _
39
from spyderlib.config import CONF
40
from spyderlib.widgets.shell import PythonShellWidget
43
def create_banner(message):
44
"""Create internal shell banner"""
45
versions = get_versions()
46
return 'Spyder %s on Python %s [%s]\n%s' % (
47
versions['spyder'], versions['python'], versions['system'], message)
50
class SysOutput(QObject):
51
"""Handle standard I/O queue"""
53
QObject.__init__(self)
55
self.lock = threading.Lock()
59
self.queue.append(val)
61
self.emit(SIGNAL("void data_avail()"))
63
def empty_queue(self):
65
s = "".join(self.queue)
70
class WidgetProxyData(object):
73
class WidgetProxy(QObject):
74
"""Handle Shell widget refresh signal"""
75
def __init__(self, input_condition):
76
QObject.__init__(self)
77
self.input_data = None
78
self.input_condition = input_condition
80
def new_prompt(self, prompt):
81
self.emit(SIGNAL("new_prompt(QString)"), prompt)
83
def set_readonly(self, state):
84
self.emit(SIGNAL("set_readonly(bool)"), state)
86
def edit(self, filename, external_editor=False):
87
self.emit(SIGNAL("edit(QString,bool)"), filename, external_editor)
89
def data_available(self):
90
"""Return True if input data is available"""
91
return self.input_data is not WidgetProxyData
93
def wait_input(self, prompt=''):
94
self.input_data = WidgetProxyData
95
self.emit(SIGNAL("wait_input(QString)"), prompt)
97
def end_input(self, cmd):
98
self.input_condition.acquire()
100
self.input_condition.notify()
101
self.input_condition.release()
104
class InternalShell(PythonShellWidget):
105
"""Shell base widget: link between PythonShellWidget and Interpreter"""
106
def __init__(self, parent=None, namespace=None, commands=[], message="",
107
max_line_count=300, font=None, debug=False, exitfunc=None,
108
profile=False, multithreaded=True, light_background=True):
109
PythonShellWidget.__init__(self, parent,
110
get_conf_path('.history_internal.py'),
113
self.set_light_background(light_background)
115
self.multithreaded = multithreaded
117
self.setMaximumBlockCount(max_line_count)
122
# Allow raw_input support:
123
self.input_loop = None
124
self.input_mode = False
126
# KeyboardInterrupt support
127
self.interrupted = False # used only for not-multithreaded mode
128
self.connect(self, SIGNAL("keyboard_interrupt()"),
129
self.keyboard_interrupt)
131
# Code completion / calltips
132
getcfg = lambda option: CONF.get('internal_console', option)
133
case_sensitive = getcfg('codecompletion/case_sensitive')
134
show_single = getcfg('codecompletion/show_single')
135
self.set_codecompletion_case(case_sensitive)
136
self.set_codecompletion_single(show_single)
138
# keyboard events management
142
self.exitfunc = exitfunc
143
self.commands = commands
144
self.message = message
145
self.interpreter = None
146
self.start_interpreter(namespace)
149
self.emit(SIGNAL("status(QString)"), '')
151
# Embedded shell -- requires the monitor (which installs the
152
# 'open_in_spyder' function in builtins)
153
if hasattr(__builtin__, 'open_in_spyder'):
154
self.connect(self, SIGNAL("go_to_error(QString)"),
155
self.open_with_external_spyder)
159
def start_interpreter(self, namespace):
160
"""Start Python interpreter"""
163
if self.interpreter is not None:
164
self.interpreter.closing()
165
self.interpreter = Interpreter(namespace, self.exitfunc,
166
SysOutput, WidgetProxy, self.debug)
167
self.connect(self.interpreter.stdout_write,
168
SIGNAL("void data_avail()"), self.stdout_avail)
169
self.connect(self.interpreter.stderr_write,
170
SIGNAL("void data_avail()"), self.stderr_avail)
171
self.connect(self.interpreter.widget_proxy,
172
SIGNAL("set_readonly(bool)"), self.setReadOnly)
173
self.connect(self.interpreter.widget_proxy,
174
SIGNAL("new_prompt(QString)"), self.new_prompt)
175
self.connect(self.interpreter.widget_proxy,
176
SIGNAL("edit(QString,bool)"), self.edit_script)
177
self.connect(self.interpreter.widget_proxy,
178
SIGNAL("wait_input(QString)"), self.wait_input)
179
if self.multithreaded:
180
self.interpreter.start()
183
banner = create_banner(self.message)
184
self.write(banner, prompt=True)
187
for cmd in self.commands:
188
self.run_command(cmd, history=False, new_prompt=False)
191
self.new_prompt(self.interpreter.p1)
192
self.emit(SIGNAL("refresh()"))
194
return self.interpreter
196
def exit_interpreter(self):
197
"""Exit interpreter"""
198
self.interpreter.exit_flag = True
199
if self.multithreaded:
200
self.interpreter.stdin_write.write('\n')
201
self.interpreter.restore_stds()
203
def edit_script(self, filename, external_editor):
204
filename = unicode(filename)
206
self.external_editor(filename)
208
self.parent().edit_script(filename)
210
def stdout_avail(self):
211
"""Data is available in stdout, let's empty the queue and write it!"""
212
data = self.interpreter.stdout_write.empty_queue()
216
def stderr_avail(self):
217
"""Data is available in stderr, let's empty the queue and write it!"""
218
data = self.interpreter.stderr_write.empty_queue()
220
self.write(data, error=True)
221
self.flush(error=True)
224
#------Raw input support
225
def wait_input(self, prompt=''):
226
"""Wait for input (raw_input support)"""
227
self.new_prompt(prompt)
229
self.input_mode = True
230
self.input_loop = QEventLoop()
231
self.input_loop.exec_()
232
self.input_loop = None
234
def end_input(self, cmd):
235
"""End of wait_input mode"""
236
self.input_mode = False
237
self.input_loop.exit()
238
self.interpreter.widget_proxy.end_input(cmd)
241
#----- Menus, actions, ...
242
def setup_context_menu(self):
243
"""Reimplement PythonShellWidget method"""
244
PythonShellWidget.setup_context_menu(self)
245
self.help_action = create_action(self, _("Help..."),
246
icon=get_std_icon('DialogHelpButton'),
248
self.menu.addAction(self.help_action)
251
"""Help on Spyder console"""
252
QMessageBox.about(self, _("Help"),
254
<p><i>%s</i><br> edit foobar.py
255
<p><i>%s</i><br> xedit foobar.py
256
<p><i>%s</i><br> run foobar.py
257
<p><i>%s</i><br> clear x, y
259
<p><i>%s</i><br> object?
260
<p><i>%s</i><br> result = oedit(object)
261
""" % (_('Shell special commands:'),
262
_('Internal editor:'),
263
_('External editor:'),
265
_('Remove references:'),
266
_('System commands:'),
268
_('GUI-based editor:')))
271
#------ External editing
272
def open_with_external_spyder(self, text):
273
"""Load file in external Spyder's editor, if available
274
This method is used only for embedded consoles
275
(could also be useful if we ever implement the magic %edit command)"""
276
match = get_error_match(unicode(text))
278
fname, lnb = match.groups()
279
__builtin__.open_in_spyder(fname, int(lnb))
281
def external_editor(self, filename, goto=-1):
282
"""Edit in an external editor
283
Recommended: SciTE (e.g. to go to line where an error did occur)"""
284
editor_path = CONF.get('internal_console', 'external_editor/path')
285
goto_option = CONF.get('internal_console', 'external_editor/gotoline')
287
if goto > 0 and goto_option:
288
Popen(r'%s "%s" %s%d' % (editor_path, filename,
291
Popen(r'%s "%s"' % (editor_path, filename))
293
self.write_error("External editor was not found:"
294
" %s\n" % editor_path)
298
def flush(self, error=False, prompt=False):
299
"""Reimplement ShellBaseWidget method"""
300
PythonShellWidget.flush(self, error=error, prompt=prompt)
302
self.interrupted = False
303
raise KeyboardInterrupt
306
#------ Clear terminal
307
def clear_terminal(self):
308
"""Reimplement ShellBaseWidget method"""
310
self.new_prompt(self.interpreter.p2 if self.interpreter.more else self.interpreter.p1)
313
#------ Keyboard events
314
def on_enter(self, command):
317
# Simple profiling test
320
self.execute_command(command)
321
self.insert_text(u"\n<Δt>=%dms\n" % (1e2*(time()-t0)))
322
self.new_prompt(self.interpreter.p1)
324
self.execute_command(command)
325
self.__flush_eventqueue()
327
def keyPressEvent(self, event):
329
Reimplement Qt Method
330
Enhanced keypress event handler
332
if self.preprocess_keyevent(event):
333
# Event was accepted in self.preprocess_keyevent
335
self.postprocess_keyevent(event)
337
def __flush_eventqueue(self):
338
"""Flush keyboard event queue"""
339
while self.eventqueue:
340
past_event = self.eventqueue.pop(0)
341
self.postprocess_keyevent(past_event)
343
#------ Command execution
344
def keyboard_interrupt(self):
345
"""Simulate keyboard interrupt"""
346
if self.multithreaded:
347
self.interpreter.raise_keyboard_interrupt()
349
if self.interpreter.more:
350
self.write_error("\nKeyboardInterrupt\n")
351
self.interpreter.more = False
352
self.new_prompt(self.interpreter.p1)
353
self.interpreter.resetbuffer()
355
self.interrupted = True
357
def execute_lines(self, lines):
359
Execute a set of lines as multiple command
360
lines: multiple lines of text to be executed as single commands
362
for line in lines.splitlines():
363
stripped_line = line.strip()
364
if stripped_line.startswith('#'):
366
self.write(line+os.linesep, flush=True)
367
self.execute_command(line+"\n")
370
def execute_command(self, cmd):
373
cmd: one-line command only, with '\n' at the end
378
if cmd.endswith('\n'):
382
self.clear_terminal()
384
self.run_command(cmd)
386
def run_command(self, cmd, history=True, new_prompt=True):
387
"""Run command in interpreter"""
392
self.add_to_history(cmd)
393
self.interpreter.stdin_write.write(cmd.encode("utf-8") + '\n')
394
if not self.multithreaded:
395
self.interpreter.run_line()
396
self.emit(SIGNAL("refresh()"))
399
#------ Code completion / Calltips
400
def _eval(self, text):
401
"""Is text a valid object?"""
402
return self.interpreter.eval(text)
404
def get_dir(self, objtxt):
405
"""Return dir(object)"""
406
obj, valid = self._eval(objtxt)
408
return getobjdir(obj)
410
def get_globals_keys(self):
411
"""Return shell globals() keys"""
412
return self.interpreter.namespace.keys()
414
def get_cdlistdir(self):
415
"""Return shell current directory list dir"""
416
return os.listdir(os.getcwdu())
418
def iscallable(self, objtxt):
419
"""Is object callable?"""
420
obj, valid = self._eval(objtxt)
424
def get_arglist(self, objtxt):
425
"""Get func/method argument list"""
426
obj, valid = self._eval(objtxt)
428
return getargtxt(obj)
430
def get__doc__(self, objtxt):
431
"""Get object __doc__"""
432
obj, valid = self._eval(objtxt)
436
def get_doc(self, objtxt):
437
"""Get object documentation"""
438
obj, valid = self._eval(objtxt)
442
def get_source(self, objtxt):
443
"""Get object source"""
444
obj, valid = self._eval(objtxt)
446
return getsource(obj)
448
def is_defined(self, objtxt, force_import=False):
449
"""Return True if object is defined"""
450
return self.interpreter.is_defined(objtxt, force_import)
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
"""Internal shell widget : PythonShellWidget + Interpreter"""
9
# pylint: disable=C0103
10
# pylint: disable=R0903
11
# pylint: disable=R0911
12
# pylint: disable=R0201
14
#FIXME: Internal shell MT: for i in range(100000): print i -> bug
18
from spyderlib.widgets.objecteditor import oedit
19
__builtin__.oedit = oedit
24
from subprocess import Popen
26
from spyderlib.qt.QtGui import QMessageBox
27
from spyderlib.qt.QtCore import SIGNAL, QObject, QEventLoop
30
from spyderlib import get_versions
31
from spyderlib.utils.qthelpers import create_action, get_std_icon
32
from spyderlib.interpreter import Interpreter
33
from spyderlib.utils.dochelpers import getargtxt, getsource, getdoc, getobjdir
34
from spyderlib.utils.misc import get_error_match
35
#TODO: remove the CONF object and make it work anyway
36
# In fact, this 'CONF' object has nothing to do in package spyderlib.widgets
37
# which should not contain anything directly related to Spyder's main app
38
from spyderlib.baseconfig import get_conf_path, _
39
from spyderlib.config import CONF
40
from spyderlib.widgets.shell import PythonShellWidget
43
def create_banner(message):
44
"""Create internal shell banner"""
45
versions = get_versions()
46
return 'Spyder %s internal shell on Python %s %dbits [%s]\n%s'\
47
% (versions['spyder'], versions['python'], versions['bitness'],
48
versions['system'], message)
51
class SysOutput(QObject):
52
"""Handle standard I/O queue"""
54
QObject.__init__(self)
56
self.lock = threading.Lock()
60
self.queue.append(val)
62
self.emit(SIGNAL("void data_avail()"))
64
def empty_queue(self):
66
s = "".join(self.queue)
71
class WidgetProxyData(object):
74
class WidgetProxy(QObject):
75
"""Handle Shell widget refresh signal"""
76
def __init__(self, input_condition):
77
QObject.__init__(self)
78
self.input_data = None
79
self.input_condition = input_condition
81
def new_prompt(self, prompt):
82
self.emit(SIGNAL("new_prompt(QString)"), prompt)
84
def set_readonly(self, state):
85
self.emit(SIGNAL("set_readonly(bool)"), state)
87
def edit(self, filename, external_editor=False):
88
self.emit(SIGNAL("edit(QString,bool)"), filename, external_editor)
90
def data_available(self):
91
"""Return True if input data is available"""
92
return self.input_data is not WidgetProxyData
94
def wait_input(self, prompt=''):
95
self.input_data = WidgetProxyData
96
self.emit(SIGNAL("wait_input(QString)"), prompt)
98
def end_input(self, cmd):
99
self.input_condition.acquire()
100
self.input_data = cmd
101
self.input_condition.notify()
102
self.input_condition.release()
105
class InternalShell(PythonShellWidget):
106
"""Shell base widget: link between PythonShellWidget and Interpreter"""
107
def __init__(self, parent=None, namespace=None, commands=[], message="",
108
max_line_count=300, font=None, debug=False, exitfunc=None,
109
profile=False, multithreaded=True, light_background=True):
110
PythonShellWidget.__init__(self, parent,
111
get_conf_path('.history_internal.py'),
114
self.set_light_background(light_background)
116
self.multithreaded = multithreaded
118
self.setMaximumBlockCount(max_line_count)
123
# Allow raw_input support:
124
self.input_loop = None
125
self.input_mode = False
127
# KeyboardInterrupt support
128
self.interrupted = False # used only for not-multithreaded mode
129
self.connect(self, SIGNAL("keyboard_interrupt()"),
130
self.keyboard_interrupt)
132
# Code completion / calltips
133
getcfg = lambda option: CONF.get('internal_console', option)
134
case_sensitive = getcfg('codecompletion/case_sensitive')
135
show_single = getcfg('codecompletion/show_single')
136
self.set_codecompletion_case(case_sensitive)
137
self.set_codecompletion_single(show_single)
139
# keyboard events management
143
self.exitfunc = exitfunc
144
self.commands = commands
145
self.message = message
146
self.interpreter = None
147
self.start_interpreter(namespace)
150
self.emit(SIGNAL("status(QString)"), '')
152
# Embedded shell -- requires the monitor (which installs the
153
# 'open_in_spyder' function in builtins)
154
if hasattr(__builtin__, 'open_in_spyder'):
155
self.connect(self, SIGNAL("go_to_error(QString)"),
156
self.open_with_external_spyder)
160
def start_interpreter(self, namespace):
161
"""Start Python interpreter"""
164
if self.interpreter is not None:
165
self.interpreter.closing()
166
self.interpreter = Interpreter(namespace, self.exitfunc,
167
SysOutput, WidgetProxy, self.debug)
168
self.connect(self.interpreter.stdout_write,
169
SIGNAL("void data_avail()"), self.stdout_avail)
170
self.connect(self.interpreter.stderr_write,
171
SIGNAL("void data_avail()"), self.stderr_avail)
172
self.connect(self.interpreter.widget_proxy,
173
SIGNAL("set_readonly(bool)"), self.setReadOnly)
174
self.connect(self.interpreter.widget_proxy,
175
SIGNAL("new_prompt(QString)"), self.new_prompt)
176
self.connect(self.interpreter.widget_proxy,
177
SIGNAL("edit(QString,bool)"), self.edit_script)
178
self.connect(self.interpreter.widget_proxy,
179
SIGNAL("wait_input(QString)"), self.wait_input)
180
if self.multithreaded:
181
self.interpreter.start()
184
banner = create_banner(self.message)
185
self.write(banner, prompt=True)
188
for cmd in self.commands:
189
self.run_command(cmd, history=False, new_prompt=False)
192
self.new_prompt(self.interpreter.p1)
193
self.emit(SIGNAL("refresh()"))
195
return self.interpreter
197
def exit_interpreter(self):
198
"""Exit interpreter"""
199
self.interpreter.exit_flag = True
200
if self.multithreaded:
201
self.interpreter.stdin_write.write('\n')
202
self.interpreter.restore_stds()
204
def edit_script(self, filename, external_editor):
205
filename = unicode(filename)
207
self.external_editor(filename)
209
self.parent().edit_script(filename)
211
def stdout_avail(self):
212
"""Data is available in stdout, let's empty the queue and write it!"""
213
data = self.interpreter.stdout_write.empty_queue()
217
def stderr_avail(self):
218
"""Data is available in stderr, let's empty the queue and write it!"""
219
data = self.interpreter.stderr_write.empty_queue()
221
self.write(data, error=True)
222
self.flush(error=True)
225
#------Raw input support
226
def wait_input(self, prompt=''):
227
"""Wait for input (raw_input support)"""
228
self.new_prompt(prompt)
230
self.input_mode = True
231
self.input_loop = QEventLoop()
232
self.input_loop.exec_()
233
self.input_loop = None
235
def end_input(self, cmd):
236
"""End of wait_input mode"""
237
self.input_mode = False
238
self.input_loop.exit()
239
self.interpreter.widget_proxy.end_input(cmd)
242
#----- Menus, actions, ...
243
def setup_context_menu(self):
244
"""Reimplement PythonShellWidget method"""
245
PythonShellWidget.setup_context_menu(self)
246
self.help_action = create_action(self, _("Help..."),
247
icon=get_std_icon('DialogHelpButton'),
249
self.menu.addAction(self.help_action)
252
"""Help on Spyder console"""
253
QMessageBox.about(self, _("Help"),
255
<p><i>%s</i><br> edit foobar.py
256
<p><i>%s</i><br> xedit foobar.py
257
<p><i>%s</i><br> run foobar.py
258
<p><i>%s</i><br> clear x, y
260
<p><i>%s</i><br> object?
261
<p><i>%s</i><br> result = oedit(object)
262
""" % (_('Shell special commands:'),
263
_('Internal editor:'),
264
_('External editor:'),
266
_('Remove references:'),
267
_('System commands:'),
269
_('GUI-based editor:')))
272
#------ External editing
273
def open_with_external_spyder(self, text):
274
"""Load file in external Spyder's editor, if available
275
This method is used only for embedded consoles
276
(could also be useful if we ever implement the magic %edit command)"""
277
match = get_error_match(unicode(text))
279
fname, lnb = match.groups()
280
__builtin__.open_in_spyder(fname, int(lnb))
282
def external_editor(self, filename, goto=-1):
283
"""Edit in an external editor
284
Recommended: SciTE (e.g. to go to line where an error did occur)"""
285
editor_path = CONF.get('internal_console', 'external_editor/path')
286
goto_option = CONF.get('internal_console', 'external_editor/gotoline')
288
if goto > 0 and goto_option:
289
Popen(r'%s "%s" %s%d' % (editor_path, filename,
292
Popen(r'%s "%s"' % (editor_path, filename))
294
self.write_error("External editor was not found:"
295
" %s\n" % editor_path)
299
def flush(self, error=False, prompt=False):
300
"""Reimplement ShellBaseWidget method"""
301
PythonShellWidget.flush(self, error=error, prompt=prompt)
303
self.interrupted = False
304
raise KeyboardInterrupt
307
#------ Clear terminal
308
def clear_terminal(self):
309
"""Reimplement ShellBaseWidget method"""
311
self.new_prompt(self.interpreter.p2 if self.interpreter.more else self.interpreter.p1)
314
#------ Keyboard events
315
def on_enter(self, command):
318
# Simple profiling test
321
self.execute_command(command)
322
self.insert_text(u"\n<Δt>=%dms\n" % (1e2*(time()-t0)))
323
self.new_prompt(self.interpreter.p1)
325
self.execute_command(command)
326
self.__flush_eventqueue()
328
def keyPressEvent(self, event):
330
Reimplement Qt Method
331
Enhanced keypress event handler
333
if self.preprocess_keyevent(event):
334
# Event was accepted in self.preprocess_keyevent
336
self.postprocess_keyevent(event)
338
def __flush_eventqueue(self):
339
"""Flush keyboard event queue"""
340
while self.eventqueue:
341
past_event = self.eventqueue.pop(0)
342
self.postprocess_keyevent(past_event)
344
#------ Command execution
345
def keyboard_interrupt(self):
346
"""Simulate keyboard interrupt"""
347
if self.multithreaded:
348
self.interpreter.raise_keyboard_interrupt()
350
if self.interpreter.more:
351
self.write_error("\nKeyboardInterrupt\n")
352
self.interpreter.more = False
353
self.new_prompt(self.interpreter.p1)
354
self.interpreter.resetbuffer()
356
self.interrupted = True
358
def execute_lines(self, lines):
360
Execute a set of lines as multiple command
361
lines: multiple lines of text to be executed as single commands
363
for line in lines.splitlines():
364
stripped_line = line.strip()
365
if stripped_line.startswith('#'):
367
self.write(line+os.linesep, flush=True)
368
self.execute_command(line+"\n")
371
def execute_command(self, cmd):
374
cmd: one-line command only, with '\n' at the end
379
if cmd.endswith('\n'):
383
self.clear_terminal()
385
self.run_command(cmd)
387
def run_command(self, cmd, history=True, new_prompt=True):
388
"""Run command in interpreter"""
393
self.add_to_history(cmd)
394
self.interpreter.stdin_write.write(cmd.encode("utf-8") + '\n')
395
if not self.multithreaded:
396
self.interpreter.run_line()
397
self.emit(SIGNAL("refresh()"))
400
#------ Code completion / Calltips
401
def _eval(self, text):
402
"""Is text a valid object?"""
403
return self.interpreter.eval(text)
405
def get_dir(self, objtxt):
406
"""Return dir(object)"""
407
obj, valid = self._eval(objtxt)
409
return getobjdir(obj)
411
def get_globals_keys(self):
412
"""Return shell globals() keys"""
413
return self.interpreter.namespace.keys()
415
def get_cdlistdir(self):
416
"""Return shell current directory list dir"""
417
return os.listdir(os.getcwdu())
419
def iscallable(self, objtxt):
420
"""Is object callable?"""
421
obj, valid = self._eval(objtxt)
425
def get_arglist(self, objtxt):
426
"""Get func/method argument list"""
427
obj, valid = self._eval(objtxt)
429
return getargtxt(obj)
431
def get__doc__(self, objtxt):
432
"""Get object __doc__"""
433
obj, valid = self._eval(objtxt)
437
def get_doc(self, objtxt):
438
"""Get object documentation"""
439
obj, valid = self._eval(objtxt)
443
def get_source(self, objtxt):
444
"""Get object source"""
445
obj, valid = self._eval(objtxt)
447
return getsource(obj)
449
def is_defined(self, objtxt, force_import=False):
450
"""Return True if object is defined"""
451
return self.interpreter.is_defined(objtxt, force_import)