1
# -*- coding: utf-8 -*-
2
# Spyder's ExternalPythonShell sitecustomize
12
# Colorization of sys.stderr (standard Python interpreter)
13
if os.environ.get("COLORIZE_SYS_STDERR", "").lower() == "true"\
14
and not os.environ.get('IPYTHON', False):
15
class StderrProxy(object):
16
"""Proxy to sys.stderr file object overriding only the `write` method
17
to provide red colorization for the whole stream, and blue-underlined
18
for traceback file links"""
20
self.old_stderr = sys.stderr
24
def __getattr__(self, name):
25
return getattr(self.old_stderr, name)
27
def write(self, text):
28
if os.name == 'nt' and '\n' not in text:
31
for text in (self.__buffer+text).splitlines(True):
32
if text.startswith(' File') \
33
and not text.startswith(' File "<'):
34
# Show error links in blue underlined text
35
colored_text = ' '+'\x1b[4;34m'+text[2:]+'\x1b[0m'
37
# Show error messages in red
38
colored_text = '\x1b[31m'+text+'\x1b[0m'
39
self.old_stderr.write(colored_text)
42
stderrproxy = StderrProxy()
45
# Prepending this spyderlib package's path to sys.path to be sure
46
# that another version of spyderlib won't be imported instead:
47
spyderlib_path = osp.dirname(__file__)
48
while not osp.isdir(osp.join(spyderlib_path, 'spyderlib')):
49
spyderlib_path = osp.abspath(osp.join(spyderlib_path, os.pardir))
50
if not spyderlib_path.startswith(sys.prefix):
51
# Spyder is not installed: moving its parent directory to the top of
52
# sys.path to be sure that this spyderlib package will be imported in
53
# the remote process (instead of another installed version of Spyder)
54
while spyderlib_path in sys.path:
55
sys.path.remove(spyderlib_path)
56
sys.path.insert(0, spyderlib_path)
57
os.environ['SPYDER_PARENT_DIR'] = spyderlib_path
60
# Set PyQt4 API to #1 or #2
61
pyqt_api = int(os.environ.get("PYQT_API", "0"))
66
for qtype in ('QString', 'QVariant'):
67
sip.setapi(qtype, pyqt_api)
68
except AttributeError:
75
mpl_backend = os.environ.get("MATPLOTLIB_BACKEND")
79
matplotlib.use(mpl_backend)
84
if os.environ.get("MATPLOTLIB_PATCH", "").lower() == "true":
86
from spyderlib import mpl_patch
92
if os.name == 'nt': # Windows platforms
94
# Setting console encoding (otherwise Python does not recognize encoding)
97
_t, _cp = locale.getdefaultlocale('LANG')
100
ctypes.windll.kernel32.SetConsoleCP(_cp)
101
ctypes.windll.kernel32.SetConsoleOutputCP(_cp)
102
except (ValueError, TypeError):
103
# Code page number in locale is not valid
108
# Workaround for IPython thread issues with win32 comdlg32
109
if os.environ.get('IPYTHON', False):
111
import win32gui, win32api
113
win32gui.GetOpenFileNameW(File=win32api.GetSystemDirectory()[:2])
114
except win32gui.error:
115
# This error is triggered intentionally
118
# Unfortunately, pywin32 is not installed...
122
# Set standard outputs encoding:
123
# (otherwise, for example, print u"é" will fail)
130
loc = locale.getdefaultlocale()
137
sys.setdefaultencoding(encoding)
138
os.environ['SPYDER_ENCODING'] = encoding
141
import sitecustomize #analysis:ignore
146
# Communication between Spyder and the remote process
147
if os.environ.get('SPYDER_SHELL_ID') is None:
150
from spyderlib.widgets.externalshell.monitor import Monitor
151
monitor = Monitor("127.0.0.1",
152
int(os.environ['SPYDER_I_PORT']),
153
int(os.environ['SPYDER_N_PORT']),
154
os.environ['SPYDER_SHELL_ID'],
155
float(os.environ['SPYDER_AR_TIMEOUT']),
156
os.environ["SPYDER_AR_STATE"].lower() == "true")
159
def open_in_spyder(source, lineno=1):
160
"""Open in Spyder's editor the source file
161
(may be a filename or a Python module/package)"""
162
if not isinstance(source, basestring):
164
source = source.__file__
165
except AttributeError:
166
raise ValueError("source argument must be either "
167
"a string or a module object")
168
if source.endswith('.pyc'):
170
monitor.notify_open_file(source, lineno=lineno)
171
__builtin__.open_in_spyder = open_in_spyder
174
# * Removing PyQt4 input hook which is not working well on Windows since
175
# opening a subprocess do not attach a real console to it
176
# (with keyboard events...)
177
# * Replacing it with our own input hook
179
# * Installing an input hook: this feature is not yet supported
181
if os.environ.get("INSTALL_QT_INPUTHOOK", "").lower() == "true"\
182
and not os.environ.get('IPYTHON', False):
183
# For now, the Spyder's input hook does not work with IPython:
184
# with IPython v0.10 or non-Windows platforms, this is not a
185
# problem. However, with IPython v0.11 on Windows, this will be
186
# fixed by patching IPython to force it to use our inputhook.
188
if os.environ["QT_API"] == 'pyqt':
189
from PyQt4 import QtCore
190
# Removing PyQt's PyOS_InputHook implementation:
191
QtCore.pyqtRemoveInputHook()
192
elif os.environ["QT_API"] == 'pyside':
193
from PySide import QtCore
194
# XXX: when PySide will implement an input hook, we will have to
200
"""Qt input hook for Spyder's console
202
This input hook wait for available stdin data (notified by
203
ExternalPythonShell through the monitor's inputhook_flag
204
attribute), and in the meantime it processes Qt events."""
205
# Refreshing variable explorer, except on first input hook call:
206
# (otherwise, on slow machines, this may freeze Spyder)
207
monitor.refresh_from_inputhook()
210
# This call fails for Python without readline support
211
# (or on Windows platforms) when PyOS_InputHook is called
212
# for the second consecutive time, because the 100-bytes
213
# stdin buffer is full.
214
# For more details, see the `PyOS_StdioReadline` function
215
# in Python source code (Parser/myreadline.c)
219
app = QtCore.QCoreApplication.instance()
220
if app and app.thread() is QtCore.QThread.currentThread():
221
timer = QtCore.QTimer()
222
QtCore.QObject.connect(timer, QtCore.SIGNAL('timeout()'),
223
app, QtCore.SLOT('quit()'))
224
monitor.toggle_inputhook_flag(False)
225
while not monitor.inputhook_flag:
227
QtCore.QCoreApplication.exec_()
229
# # Socket-based alternative:
230
# socket = QtNetwork.QLocalSocket()
231
# socket.connectToServer(os.environ['SPYDER_SHELL_ID'])
232
# socket.waitForConnected(-1)
233
# while not socket.waitForReadyRead(10):
235
# QtCore.QCoreApplication.exec_()
238
# socket.disconnectFromServer()
241
# Installing Spyder's PyOS_InputHook implementation:
243
cb_pyfunctype = ctypes.PYFUNCTYPE(ctypes.c_int)(qt_inputhook)
244
pyos_ih = ctypes.c_void_p.in_dll(ctypes.pythonapi, "PyOS_InputHook")
245
pyos_ih.value = ctypes.cast(cb_pyfunctype, ctypes.c_void_p).value
247
# Quite limited feature: notify only when a result is displayed in
248
# console (does not notify at every prompt)
249
def displayhook(obj):
250
sys.__displayhook__(obj)
253
sys.displayhook = displayhook
256
#===============================================================================
257
# Monkey-patching pdb
258
#===============================================================================
259
class SpyderPdb(pdb.Pdb):
260
def set_spyder_breakpoints(self):
261
self.clear_all_breaks()
262
#------Really deleting all breakpoints:
263
for bp in bdb.Breakpoint.bpbynumber:
266
bdb.Breakpoint.next = 1
267
bdb.Breakpoint.bplist = {}
268
bdb.Breakpoint.bpbynumber = [None]
270
from spyderlib.config import CONF
272
if CONF.get('run', 'breakpoints/enabled', True):
273
breakpoints = CONF.get('run', 'breakpoints', {})
275
for fname, data in breakpoints.iteritems():
276
for linenumber, condition in data:
278
self.set_break(self.canonic(fname), linenumber,
281
def notify_spyder(self, frame):
284
fname = self.canonic(frame.f_code.co_filename)
285
lineno = frame.f_lineno
286
if isinstance(fname, basestring) and isinstance(lineno, int):
287
if osp.isfile(fname) and monitor is not None:
288
monitor.notify_pdb_step(fname, lineno)
292
def monkeypatch_method(cls, patch_name):
293
# This function's code was inspired from the following thread:
294
# "[Python-Dev] Monkeypatching idioms -- elegant or ugly?"
295
# by Robert Brewer <fumanchu at aminus.org>
296
# (Tue Jan 15 19:13:25 CET 2008)
298
Add the decorated method to the given class; replace as needed.
300
If the named method already exists on the given class, it will
301
be replaced, and a reference to the old method is created as
302
cls._old<patch_name><name>. If the "_old_<patch_name>_<name>" attribute
303
already exists, KeyError is raised.
306
fname = func.__name__
307
old_func = getattr(cls, fname, None)
308
if old_func is not None:
309
# Add the old func to a list of old funcs.
310
old_ref = "_old_%s_%s" % (patch_name, fname)
311
#print old_ref, old_func
312
old_attr = getattr(cls, old_ref, None)
314
setattr(cls, old_ref, old_func)
316
raise KeyError("%s.%s already exists."
317
% (cls.__name__, old_ref))
318
setattr(cls, fname, func)
322
@monkeypatch_method(pdb.Pdb, 'Pdb')
323
def user_return(self, frame, return_value):
324
"""This function is called when a return trap is set here."""
325
# This is useful when debugging in an active interpreter (otherwise,
326
# the debugger will stop before reaching the target file)
327
if self._wait_for_mainpyfile:
328
if (self.mainpyfile != self.canonic(frame.f_code.co_filename)
329
or frame.f_lineno<= 0):
331
self._wait_for_mainpyfile = 0
332
self._old_Pdb_user_return(frame, return_value)
334
@monkeypatch_method(pdb.Pdb, 'Pdb')
335
def interaction(self, frame, traceback):
336
self.setup(frame, traceback)
337
self.notify_spyder(frame) #-----Spyder-specific-------------------------
338
self.print_stack_entry(self.stack[self.curindex])
342
@monkeypatch_method(pdb.Pdb, 'Pdb')
344
self._old_Pdb_reset()
345
if monitor is not None:
346
monitor.register_pdb_session(self)
347
self.set_spyder_breakpoints()
349
#XXX: notify spyder on any pdb command (is that good or too lazy? i.e. is more
350
# specific behaviour desired?)
351
@monkeypatch_method(pdb.Pdb, 'Pdb')
352
def postcmd(self, stop, line):
353
self.notify_spyder(self.curframe)
354
return self._old_Pdb_postcmd(stop, line)
357
# Restoring (almost) original sys.path:
358
# (Note: do not remove spyderlib_path from sys.path because if Spyder has been
359
# installed using python setup.py install, then this could remove the
360
# 'site-packages' directory from sys.path!)
362
sys.path.remove(osp.join(spyderlib_path,
363
"spyderlib", "widgets", "externalshell"))
367
# Ignore PyQt4's sip API changes (this should be used wisely -e.g. for
368
# debugging- as dynamic API change is not supported by PyQt)
369
if os.environ.get("IGNORE_SIP_SETAPI_ERRORS", "").lower() == "true":
372
from sip import setapi as original_setapi
373
def patched_setapi(name, no):
375
original_setapi(name, no)
376
except ValueError, msg:
377
print >>sys.stderr, "Warning/PyQt4-Spyder (%s)" % str(msg)
378
sip.setapi = patched_setapi
383
# The following classes and functions are mainly intended to be used from
384
# an interactive Python/IPython session
385
class UserModuleDeleter(object):
387
User Module Deleter (UMD) aims at deleting user modules
388
to force Python to deeply reload them during import
390
pathlist [list]: blacklist in terms of module path
391
namelist [list]: blacklist in terms of module name
393
def __init__(self, namelist=None, pathlist=None):
396
self.namelist = namelist+['sitecustomize', 'spyderlib', 'spyderplugins']
399
self.pathlist = pathlist
400
self.previous_modules = sys.modules.keys()
402
def is_module_blacklisted(self, modname, modpath):
403
for path in [sys.prefix]+self.pathlist:
404
if modpath.startswith(path):
407
return set(modname.split('.')) & set(self.namelist)
409
def run(self, verbose=False):
411
Del user modules to force Python to deeply reload them
413
Do not del modules which are considered as system modules, i.e.
414
modules installed in subdirectories of Python interpreter's binary
418
for modname, module in sys.modules.items():
419
if modname not in self.previous_modules:
420
modpath = getattr(module, '__file__', None)
422
# *module* is a C module that is statically linked into the
423
# interpreter. There is no way to know its path, so we
424
# choose to ignore it.
426
if not self.is_module_blacklisted(modname, modpath):
428
del sys.modules[modname]
430
print "\x1b[4;33m%s\x1b[24m%s\x1b[0m" % ("UMD has deleted",
437
"""Return current Python/IPython interpreter globals namespace"""
438
from __main__ import __dict__ as namespace
439
if hasattr(__builtin__, '__IPYTHON__'):
441
shell = __builtin__.__IPYTHON__
444
shell = namespace.get('__ipythonshell__')
445
if shell is not None and hasattr(shell, 'user_ns'):
452
def runfile(filename, args=None, wdir=None, namespace=None):
455
args: command line arguments (string)
456
wdir: working directory
459
filename = filename.decode('utf-8')
460
except (UnicodeError, TypeError):
463
if os.environ.get("UMD_ENABLED", "").lower() == "true":
465
namelist = os.environ.get("UMD_NAMELIST", None)
466
if namelist is not None:
467
namelist = namelist.split(',')
468
__umd__ = UserModuleDeleter(namelist=namelist)
470
verbose = os.environ.get("UMD_VERBOSE", "").lower() == "true"
471
__umd__.run(verbose=verbose)
472
if args is not None and not isinstance(args, basestring):
473
raise TypeError("expected a character buffer object")
474
if namespace is None:
475
namespace = _get_globals()
476
namespace['__file__'] = filename
477
sys.argv = [filename]
479
for arg in args.split():
483
wdir = wdir.decode('utf-8')
484
except (UnicodeError, TypeError):
487
execfile(filename, namespace)
489
namespace.pop('__file__')
491
__builtin__.runfile = runfile
494
def debugfile(filename, args=None, wdir=None):
497
args: command line arguments (string)
498
wdir: working directory
501
filename = debugger.canonic(filename)
502
debugger._wait_for_mainpyfile = 1
503
debugger.mainpyfile = filename
504
debugger._user_requested_quit = 0
505
debugger.run("runfile(%r, args=%r, wdir=%r)" % (filename, args, wdir))
507
__builtin__.debugfile = debugfile
511
"""Evaluate special commands
512
(analog to IPython's magic commands but far less powerful/complete)"""
513
assert command.startswith(('%', '!'))
514
system_command = command.startswith('!')
515
command = command[1:].strip()
518
if command.startswith('cd '):
521
from subprocess import Popen, PIPE
522
Popen(command, shell=True, stdin=PIPE)
526
namespace = _get_globals()
528
clear_match = re.match(r"^clear ([a-zA-Z0-9_, ]+)", command)
529
cd_match = re.match(r"^cd \"?\'?([a-zA-Z0-9_\ \:\\\/\.]+)", command)
531
os.chdir(eval('r"%s"' % cd_match.groups()[0].strip()))
533
varnames = clear_match.groups()[0].replace(' ', '').split(',')
534
for varname in varnames:
536
namespace.pop(varname)
539
elif command in ('cd', 'pwd'):
541
elif command == 'ls':
546
elif command == 'scientific':
547
from spyderlib import baseconfig
548
execfile(baseconfig.SCIENTIFIC_STARTUP, namespace)
550
raise NotImplementedError, "Unsupported command: '%s'" % command
552
__builtin__.evalsc = evalsc
555
# Restoring original PYTHONPATH
557
os.environ['PYTHONPATH'] = os.environ['OLD_PYTHONPATH']
558
del os.environ['OLD_PYTHONPATH']
560
if os.environ.get('PYTHONPATH') is not None:
561
del os.environ['PYTHONPATH']
1
# -*- coding: utf-8 -*-
2
# Spyder's ExternalPythonShell sitecustomize
12
# Colorization of sys.stderr (standard Python interpreter)
13
if os.environ.get("COLORIZE_SYS_STDERR", "").lower() == "true":
14
class StderrProxy(object):
15
"""Proxy to sys.stderr file object overriding only the `write` method
16
to provide red colorization for the whole stream, and blue-underlined
17
for traceback file links"""
19
self.old_stderr = sys.stderr
23
def __getattr__(self, name):
24
return getattr(self.old_stderr, name)
26
def write(self, text):
27
if os.name == 'nt' and '\n' not in text:
30
for text in (self.__buffer+text).splitlines(True):
31
if text.startswith(' File') \
32
and not text.startswith(' File "<'):
33
# Show error links in blue underlined text
34
colored_text = ' '+'\x1b[4;34m'+text[2:]+'\x1b[0m'
36
# Show error messages in red
37
colored_text = '\x1b[31m'+text+'\x1b[0m'
38
self.old_stderr.write(colored_text)
41
stderrproxy = StderrProxy()
44
# Prepending this spyderlib package's path to sys.path to be sure
45
# that another version of spyderlib won't be imported instead:
46
spyderlib_path = osp.dirname(__file__)
47
while not osp.isdir(osp.join(spyderlib_path, 'spyderlib')):
48
spyderlib_path = osp.abspath(osp.join(spyderlib_path, os.pardir))
49
if not spyderlib_path.startswith(sys.prefix):
50
# Spyder is not installed: moving its parent directory to the top of
51
# sys.path to be sure that this spyderlib package will be imported in
52
# the remote process (instead of another installed version of Spyder)
53
while spyderlib_path in sys.path:
54
sys.path.remove(spyderlib_path)
55
sys.path.insert(0, spyderlib_path)
56
os.environ['SPYDER_PARENT_DIR'] = spyderlib_path
59
# Set PyQt4 API to #1 or #2
60
pyqt_api = int(os.environ.get("PYQT_API", "0"))
65
for qtype in ('QString', 'QVariant'):
66
sip.setapi(qtype, pyqt_api)
67
except AttributeError:
74
mpl_backend = os.environ.get("MATPLOTLIB_BACKEND")
78
matplotlib.use(mpl_backend)
83
if os.environ.get("MATPLOTLIB_PATCH", "").lower() == "true":
85
from spyderlib import mpl_patch
91
if os.name == 'nt': # Windows platforms
93
# Setting console encoding (otherwise Python does not recognize encoding)
96
_t, _cp = locale.getdefaultlocale('LANG')
99
ctypes.windll.kernel32.SetConsoleCP(_cp)
100
ctypes.windll.kernel32.SetConsoleOutputCP(_cp)
101
except (ValueError, TypeError):
102
# Code page number in locale is not valid
108
# Set standard outputs encoding:
109
# (otherwise, for example, print u"é" will fail)
116
loc = locale.getdefaultlocale()
123
sys.setdefaultencoding(encoding)
124
os.environ['SPYDER_ENCODING'] = encoding
127
import sitecustomize #analysis:ignore
132
# Communication between Spyder and the remote process
133
if os.environ.get('SPYDER_SHELL_ID') is None:
136
from spyderlib.widgets.externalshell.monitor import Monitor
137
monitor = Monitor("127.0.0.1",
138
int(os.environ['SPYDER_I_PORT']),
139
int(os.environ['SPYDER_N_PORT']),
140
os.environ['SPYDER_SHELL_ID'],
141
float(os.environ['SPYDER_AR_TIMEOUT']),
142
os.environ["SPYDER_AR_STATE"].lower() == "true")
145
def open_in_spyder(source, lineno=1):
147
Open a source file in Spyder's editor (it could be a filename or a
148
Python module/package).
150
If you want to use IPython's %edit use %ed instead
153
source = sys.modules[source]
156
if not isinstance(source, basestring):
158
source = source.__file__
159
except AttributeError:
160
print "The argument must be either a string or a module object"
161
if source.endswith('.pyc'):
163
source = osp.abspath(source)
164
if osp.exists(source):
165
monitor.notify_open_file(source, lineno=lineno)
167
print "Can't open file %s" % source
168
__builtin__.open_in_spyder = open_in_spyder
171
# * Removing PyQt4 input hook which is not working well on Windows since
172
# opening a subprocess do not attach a real console to it
173
# (with keyboard events...)
174
# * Replacing it with our own input hook
176
# * Installing an input hook: this feature is not yet supported
178
if os.environ.get("INSTALL_QT_INPUTHOOK", "").lower() == "true":
179
if os.environ["QT_API"] == 'pyqt':
180
from PyQt4 import QtCore
181
# Removing PyQt's PyOS_InputHook implementation:
182
QtCore.pyqtRemoveInputHook()
183
elif os.environ["QT_API"] == 'pyside':
184
from PySide import QtCore
185
# XXX: when PySide will implement an input hook, we will have to
191
"""Qt input hook for Spyder's console
193
This input hook wait for available stdin data (notified by
194
ExternalPythonShell through the monitor's inputhook_flag
195
attribute), and in the meantime it processes Qt events."""
196
# Refreshing variable explorer, except on first input hook call:
197
# (otherwise, on slow machines, this may freeze Spyder)
198
monitor.refresh_from_inputhook()
201
# This call fails for Python without readline support
202
# (or on Windows platforms) when PyOS_InputHook is called
203
# for the second consecutive time, because the 100-bytes
204
# stdin buffer is full.
205
# For more details, see the `PyOS_StdioReadline` function
206
# in Python source code (Parser/myreadline.c)
210
app = QtCore.QCoreApplication.instance()
211
if app and app.thread() is QtCore.QThread.currentThread():
212
timer = QtCore.QTimer()
213
QtCore.QObject.connect(timer, QtCore.SIGNAL('timeout()'),
214
app, QtCore.SLOT('quit()'))
215
monitor.toggle_inputhook_flag(False)
216
while not monitor.inputhook_flag:
218
QtCore.QCoreApplication.exec_()
220
# # Socket-based alternative:
221
# socket = QtNetwork.QLocalSocket()
222
# socket.connectToServer(os.environ['SPYDER_SHELL_ID'])
223
# socket.waitForConnected(-1)
224
# while not socket.waitForReadyRead(10):
226
# QtCore.QCoreApplication.exec_()
229
# socket.disconnectFromServer()
232
# Installing Spyder's PyOS_InputHook implementation:
234
cb_pyfunctype = ctypes.PYFUNCTYPE(ctypes.c_int)(qt_inputhook)
235
pyos_ih = ctypes.c_void_p.in_dll(ctypes.pythonapi, "PyOS_InputHook")
236
pyos_ih.value = ctypes.cast(cb_pyfunctype, ctypes.c_void_p).value
238
# Quite limited feature: notify only when a result is displayed in
239
# console (does not notify at every prompt)
240
def displayhook(obj):
241
sys.__displayhook__(obj)
244
sys.displayhook = displayhook
247
#===============================================================================
248
# Monkey-patching pdb
249
#===============================================================================
250
class SpyderPdb(pdb.Pdb):
251
def set_spyder_breakpoints(self):
252
self.clear_all_breaks()
253
#------Really deleting all breakpoints:
254
for bp in bdb.Breakpoint.bpbynumber:
257
bdb.Breakpoint.next = 1
258
bdb.Breakpoint.bplist = {}
259
bdb.Breakpoint.bpbynumber = [None]
261
from spyderlib.config import CONF
263
if CONF.get('run', 'breakpoints/enabled', True):
264
breakpoints = CONF.get('run', 'breakpoints', {})
266
for fname, data in breakpoints.iteritems():
267
for linenumber, condition in data:
269
self.set_break(self.canonic(fname), linenumber,
272
def notify_spyder(self, frame):
275
fname = self.canonic(frame.f_code.co_filename)
276
lineno = frame.f_lineno
277
if isinstance(fname, basestring) and isinstance(lineno, int):
278
if osp.isfile(fname) and monitor is not None:
279
monitor.notify_pdb_step(fname, lineno)
283
#XXX: I know, this function is now also implemented as is in utils/misc.py but
284
# I'm kind of reluctant to import spyderlib in sitecustomize, even if this
285
# import is very clean.
286
def monkeypatch_method(cls, patch_name):
287
# This function's code was inspired from the following thread:
288
# "[Python-Dev] Monkeypatching idioms -- elegant or ugly?"
289
# by Robert Brewer <fumanchu at aminus.org>
290
# (Tue Jan 15 19:13:25 CET 2008)
292
Add the decorated method to the given class; replace as needed.
294
If the named method already exists on the given class, it will
295
be replaced, and a reference to the old method is created as
296
cls._old<patch_name><name>. If the "_old_<patch_name>_<name>" attribute
297
already exists, KeyError is raised.
300
fname = func.__name__
301
old_func = getattr(cls, fname, None)
302
if old_func is not None:
303
# Add the old func to a list of old funcs.
304
old_ref = "_old_%s_%s" % (patch_name, fname)
305
#print old_ref, old_func
306
old_attr = getattr(cls, old_ref, None)
308
setattr(cls, old_ref, old_func)
310
raise KeyError("%s.%s already exists."
311
% (cls.__name__, old_ref))
312
setattr(cls, fname, func)
316
@monkeypatch_method(pdb.Pdb, 'Pdb')
317
def user_return(self, frame, return_value):
318
"""This function is called when a return trap is set here."""
319
# This is useful when debugging in an active interpreter (otherwise,
320
# the debugger will stop before reaching the target file)
321
if self._wait_for_mainpyfile:
322
if (self.mainpyfile != self.canonic(frame.f_code.co_filename)
323
or frame.f_lineno<= 0):
325
self._wait_for_mainpyfile = 0
326
self._old_Pdb_user_return(frame, return_value)
328
@monkeypatch_method(pdb.Pdb, 'Pdb')
329
def interaction(self, frame, traceback):
330
self.setup(frame, traceback)
331
self.notify_spyder(frame) #-----Spyder-specific-------------------------
332
self.print_stack_entry(self.stack[self.curindex])
336
@monkeypatch_method(pdb.Pdb, 'Pdb')
338
self._old_Pdb_reset()
339
if monitor is not None:
340
monitor.register_pdb_session(self)
341
self.set_spyder_breakpoints()
343
#XXX: notify spyder on any pdb command (is that good or too lazy? i.e. is more
344
# specific behaviour desired?)
345
@monkeypatch_method(pdb.Pdb, 'Pdb')
346
def postcmd(self, stop, line):
347
self.notify_spyder(self.curframe)
348
return self._old_Pdb_postcmd(stop, line)
351
# Restoring (almost) original sys.path:
352
# (Note: do not remove spyderlib_path from sys.path because if Spyder has been
353
# installed using python setup.py install, then this could remove the
354
# 'site-packages' directory from sys.path!)
356
sys.path.remove(osp.join(spyderlib_path,
357
"spyderlib", "widgets", "externalshell"))
361
# Ignore PyQt4's sip API changes (this should be used wisely -e.g. for
362
# debugging- as dynamic API change is not supported by PyQt)
363
if os.environ.get("IGNORE_SIP_SETAPI_ERRORS", "").lower() == "true":
366
from sip import setapi as original_setapi
367
def patched_setapi(name, no):
369
original_setapi(name, no)
370
except ValueError, msg:
371
print >>sys.stderr, "Warning/PyQt4-Spyder (%s)" % str(msg)
372
sip.setapi = patched_setapi
377
# The following classes and functions are mainly intended to be used from
378
# an interactive Python session
379
class UserModuleDeleter(object):
381
User Module Deleter (UMD) aims at deleting user modules
382
to force Python to deeply reload them during import
384
pathlist [list]: blacklist in terms of module path
385
namelist [list]: blacklist in terms of module name
387
def __init__(self, namelist=None, pathlist=None):
390
self.namelist = namelist+['sitecustomize', 'spyderlib', 'spyderplugins']
393
self.pathlist = pathlist
394
self.previous_modules = sys.modules.keys()
396
def is_module_blacklisted(self, modname, modpath):
397
for path in [sys.prefix]+self.pathlist:
398
if modpath.startswith(path):
401
return set(modname.split('.')) & set(self.namelist)
403
def run(self, verbose=False):
405
Del user modules to force Python to deeply reload them
407
Do not del modules which are considered as system modules, i.e.
408
modules installed in subdirectories of Python interpreter's binary
412
for modname, module in sys.modules.items():
413
if modname not in self.previous_modules:
414
modpath = getattr(module, '__file__', None)
416
# *module* is a C module that is statically linked into the
417
# interpreter. There is no way to know its path, so we
418
# choose to ignore it.
420
if not self.is_module_blacklisted(modname, modpath):
422
del sys.modules[modname]
424
print "\x1b[4;33m%s\x1b[24m%s\x1b[0m" % ("UMD has deleted",
431
"""Return current Python interpreter globals namespace"""
432
from __main__ import __dict__ as namespace
433
shell = namespace.get('__ipythonshell__')
434
if shell is not None and hasattr(shell, 'user_ns'):
435
# IPython 0.13+ kernel
443
def runfile(filename, args=None, wdir=None, namespace=None):
446
args: command line arguments (string)
447
wdir: working directory
450
filename = filename.decode('utf-8')
451
except (UnicodeError, TypeError):
454
if os.environ.get("UMD_ENABLED", "").lower() == "true":
456
namelist = os.environ.get("UMD_NAMELIST", None)
457
if namelist is not None:
458
namelist = namelist.split(',')
459
__umd__ = UserModuleDeleter(namelist=namelist)
461
verbose = os.environ.get("UMD_VERBOSE", "").lower() == "true"
462
__umd__.run(verbose=verbose)
463
if args is not None and not isinstance(args, basestring):
464
raise TypeError("expected a character buffer object")
465
if namespace is None:
466
namespace = _get_globals()
467
namespace['__file__'] = filename
468
sys.argv = [filename]
470
for arg in args.split():
474
wdir = wdir.decode('utf-8')
475
except (UnicodeError, TypeError):
478
execfile(filename, namespace)
480
namespace.pop('__file__')
482
__builtin__.runfile = runfile
485
def debugfile(filename, args=None, wdir=None):
488
args: command line arguments (string)
489
wdir: working directory
492
filename = debugger.canonic(filename)
493
debugger._wait_for_mainpyfile = 1
494
debugger.mainpyfile = filename
495
debugger._user_requested_quit = 0
496
debugger.run("runfile(%r, args=%r, wdir=%r)" % (filename, args, wdir))
498
__builtin__.debugfile = debugfile
502
"""Evaluate special commands
503
(analog to IPython's magic commands but far less powerful/complete)"""
504
assert command.startswith(('%', '!'))
505
system_command = command.startswith('!')
506
command = command[1:].strip()
509
if command.startswith('cd '):
512
from subprocess import Popen, PIPE
513
Popen(command, shell=True, stdin=PIPE)
517
namespace = _get_globals()
519
clear_match = re.match(r"^clear ([a-zA-Z0-9_, ]+)", command)
520
cd_match = re.match(r"^cd \"?\'?([a-zA-Z0-9_\ \:\\\/\.]+)", command)
522
os.chdir(eval('r"%s"' % cd_match.groups()[0].strip()))
524
varnames = clear_match.groups()[0].replace(' ', '').split(',')
525
for varname in varnames:
527
namespace.pop(varname)
530
elif command in ('cd', 'pwd'):
532
elif command == 'ls':
537
elif command == 'scientific':
538
from spyderlib import baseconfig
539
execfile(baseconfig.SCIENTIFIC_STARTUP, namespace)
541
raise NotImplementedError, "Unsupported command: '%s'" % command
543
__builtin__.evalsc = evalsc
546
# Restoring original PYTHONPATH
548
os.environ['PYTHONPATH'] = os.environ['OLD_PYTHONPATH']
549
del os.environ['OLD_PYTHONPATH']
551
if os.environ.get('PYTHONPATH') is not None:
552
del os.environ['PYTHONPATH']