##// END OF EJS Templates
Cleanup check_sources and remove hard tabs from some files....
Fernando Perez -
Show More
@@ -1,35 +1,35 b''
1 1 # encoding: utf-8
2 2 """
3 3 setup.py
4 4
5 5 Setuptools installer script for generating a Cocoa plugin for the
6 6 IPython cocoa frontend
7 7
8 8 Author: Barry Wark
9 9 """
10 10 __docformat__ = "restructuredtext en"
11 11
12 12 #-----------------------------------------------------------------------------
13 13 # Copyright (C) 2008 The IPython Development Team
14 14 #
15 15 # Distributed under the terms of the BSD License. The full license is in
16 16 # the file COPYING, distributed as part of this software.
17 17 #-----------------------------------------------------------------------------
18 18
19 19 from setuptools import setup
20 20
21 21 infoPlist = dict(
22 CFBundleDevelopmentRegion='English',
23 CFBundleIdentifier='org.scipy.ipython.cocoa_frontend',
24 NSPrincipalClass='IPythonCocoaController',
22 CFBundleDevelopmentRegion='English',
23 CFBundleIdentifier='org.scipy.ipython.cocoa_frontend',
24 NSPrincipalClass='IPythonCocoaController',
25 25 )
26 26
27 27 setup(
28 plugin=['IPythonCocoaFrontendLoader.py'],
28 plugin=['IPythonCocoaFrontendLoader.py'],
29 29 setup_requires=['py2app'],
30 options=dict(py2app=dict(
31 plist=infoPlist,
32 site_packages=True,
33 excludes=['IPython','twisted','PyObjCTools']
34 )),
30 options=dict(py2app=dict(
31 plist=infoPlist,
32 site_packages=True,
33 excludes=['IPython','twisted','PyObjCTools']
34 )),
35 35 ) No newline at end of file
@@ -1,525 +1,525 b''
1 1 #!/usr/bin/python
2 2 # -*- coding: iso-8859-15 -*-
3 3 '''
4 4 Provides IPython remote instance.
5 5
6 6 @author: Laurent Dufrechou
7 7 laurent.dufrechou _at_ gmail.com
8 8 @license: BSD
9 9
10 10 All rights reserved. This program and the accompanying materials are made
11 11 available under the terms of the BSD which accompanies this distribution, and
12 12 is available at U{http://www.opensource.org/licenses/bsd-license.php}
13 13 '''
14 14
15 15 __version__ = 0.9
16 16 __author__ = "Laurent Dufrechou"
17 17 __email__ = "laurent.dufrechou _at_ gmail.com"
18 18 __license__ = "BSD"
19 19
20 20 import re
21 21 import sys
22 22 import os
23 23 import locale
24 24 from thread_ex import ThreadEx
25 25
26 26 try:
27 27 import IPython
28 28 except Exception,e:
29 29 print "Error importing IPython (%s)" % str(e)
30 30 raise Exception, e
31 31
32 32 ##############################################################################
33 33 class _Helper(object):
34 34 """Redefine the built-in 'help'.
35 35 This is a wrapper around pydoc.help (with a twist).
36 36 """
37 37
38 38 def __init__(self, pager):
39 39 self._pager = pager
40 40
41 41 def __repr__(self):
42 42 return "Type help() for interactive help, " \
43 43 "or help(object) for help about object."
44 44
45 45 def __call__(self, *args, **kwds):
46 46 class DummyWriter(object):
47 '''Dumy class to handle help output'''
47 '''Dumy class to handle help output'''
48 48 def __init__(self, pager):
49 49 self._pager = pager
50 50
51 51 def write(self, data):
52 52 '''hook to fill self._pager'''
53 53 self._pager(data)
54 54
55 55 import pydoc
56 56 pydoc.help.output = DummyWriter(self._pager)
57 57 pydoc.help.interact = lambda :1
58 58
59 59 return pydoc.help(*args, **kwds)
60 60
61 61
62 62 ##############################################################################
63 63 class _CodeExecutor(ThreadEx):
64 64 ''' Thread that execute ipython code '''
65 65 def __init__(self, instance):
66 66 ThreadEx.__init__(self)
67 67 self.instance = instance
68 68
69 69 def run(self):
70 70 '''Thread main loop'''
71 71 try:
72 72 self.instance._doc_text = None
73 73 self.instance._help_text = None
74 74 self.instance._execute()
75 75 # used for uper class to generate event after execution
76 76 self.instance._after_execute()
77 77
78 78 except KeyboardInterrupt:
79 79 pass
80 80
81 81
82 82 ##############################################################################
83 83 class NonBlockingIPShell(object):
84 84 '''
85 85 Create an IPython instance, running the commands in a separate,
86 86 non-blocking thread.
87 87 This allows embedding in any GUI without blockage.
88 88
89 89 Note: The ThreadEx class supports asynchroneous function call
90 90 via raise_exc()
91 91 '''
92 92
93 93 def __init__(self, argv=[], user_ns={}, user_global_ns=None,
94 94 cin=None, cout=None, cerr=None,
95 95 ask_exit_handler=None):
96 96 '''
97 97 @param argv: Command line options for IPython
98 98 @type argv: list
99 99 @param user_ns: User namespace.
100 100 @type user_ns: dictionary
101 101 @param user_global_ns: User global namespace.
102 102 @type user_global_ns: dictionary.
103 103 @param cin: Console standard input.
104 104 @type cin: IO stream
105 105 @param cout: Console standard output.
106 106 @type cout: IO stream
107 107 @param cerr: Console standard error.
108 108 @type cerr: IO stream
109 109 @param exit_handler: Replacement for builtin exit() function
110 110 @type exit_handler: function
111 111 @param time_loop: Define the sleep time between two thread's loop
112 112 @type int
113 113 '''
114 114 #ipython0 initialisation
115 115 self._IP = None
116 116 self.init_ipython0(argv, user_ns, user_global_ns,
117 117 cin, cout, cerr,
118 118 ask_exit_handler)
119 119
120 120 #vars used by _execute
121 121 self._iter_more = 0
122 122 self._history_level = 0
123 123 self._complete_sep = re.compile('[\s\{\}\[\]\(\)\=]')
124 124 self._prompt = str(self._IP.outputcache.prompt1).strip()
125 125
126 126 #thread working vars
127 127 self._line_to_execute = ''
128 128 self._threading = True
129 129
130 130 #vars that will be checked by GUI loop to handle thread states...
131 131 #will be replaced later by PostEvent GUI funtions...
132 132 self._doc_text = None
133 133 self._help_text = None
134 134 self._add_button = None
135 135
136 136 def init_ipython0(self, argv=[], user_ns={}, user_global_ns=None,
137 137 cin=None, cout=None, cerr=None,
138 138 ask_exit_handler=None):
139 139 ''' Initialize an ipython0 instance '''
140 140
141 141 #first we redefine in/out/error functions of IPython
142 142 #BUG: we've got a limitation form ipython0 there
143 143 #only one instance can be instanciated else tehre will be
144 144 #cin/cout/cerr clash...
145 145 if cin:
146 146 IPython.genutils.Term.cin = cin
147 147 if cout:
148 148 IPython.genutils.Term.cout = cout
149 149 if cerr:
150 150 IPython.genutils.Term.cerr = cerr
151 151
152 152 excepthook = sys.excepthook
153 153
154 154 #Hack to save sys.displayhook, because ipython seems to overwrite it...
155 155 self.sys_displayhook_ori = sys.displayhook
156 156
157 157 self._IP = IPython.Shell.make_IPython(
158 158 argv,user_ns=user_ns,
159 159 user_global_ns=user_global_ns,
160 160 embedded=True,
161 161 shell_class=IPython.Shell.InteractiveShell)
162 162
163 163 #we save ipython0 displayhook and we restore sys.displayhook
164 164 self.displayhook = sys.displayhook
165 165 sys.displayhook = self.sys_displayhook_ori
166 166
167 167 #we replace IPython default encoding by wx locale encoding
168 168 loc = locale.getpreferredencoding()
169 169 if loc:
170 170 self._IP.stdin_encoding = loc
171 171 #we replace the ipython default pager by our pager
172 172 self._IP.set_hook('show_in_pager', self._pager)
173 173
174 174 #we replace the ipython default shell command caller
175 175 #by our shell handler
176 176 self._IP.set_hook('shell_hook', self._shell)
177 177
178 178 #we replace the ipython default input command caller by our method
179 179 IPython.iplib.raw_input_original = self._raw_input_original
180 180 #we replace the ipython default exit command by our method
181 181 self._IP.exit = ask_exit_handler
182 182 #we replace the help command
183 183 self._IP.user_ns['help'] = _Helper(self._pager_help)
184 184
185 185 #we disable cpase magic... until we found a way to use it properly.
186 186 #import IPython.ipapi
187 187 ip = IPython.ipapi.get()
188 188 def bypass_magic(self, arg):
189 189 print '%this magic is currently disabled.'
190 190 ip.expose_magic('cpaste', bypass_magic)
191 191
192 192 import __builtin__
193 193 __builtin__.raw_input = self._raw_input
194 194
195 195 sys.excepthook = excepthook
196 196
197 197 #----------------------- Thread management section ----------------------
198 198 def do_execute(self, line):
199 199 """
200 200 Tell the thread to process the 'line' command
201 201 """
202 202
203 203 self._line_to_execute = line
204 204
205 205 if self._threading:
206 206 #we launch the ipython line execution in a thread to make it
207 207 #interruptible with include it in self namespace to be able
208 208 #to call ce.raise_exc(KeyboardInterrupt)
209 209 self.ce = _CodeExecutor(self)
210 210 self.ce.start()
211 211 else:
212 212 try:
213 213 self._doc_text = None
214 214 self._help_text = None
215 215 self._execute()
216 216 # used for uper class to generate event after execution
217 217 self._after_execute()
218 218
219 219 except KeyboardInterrupt:
220 220 pass
221 221
222 222 #----------------------- IPython management section ----------------------
223 223 def get_threading(self):
224 224 """
225 225 Returns threading status, is set to True, then each command sent to
226 226 the interpreter will be executed in a separated thread allowing,
227 227 for example, breaking a long running commands.
228 228 Disallowing it, permits better compatibilty with instance that is embedding
229 229 IPython instance.
230 230
231 231 @return: Execution method
232 232 @rtype: bool
233 233 """
234 234 return self._threading
235 235
236 236 def set_threading(self, state):
237 237 """
238 238 Sets threading state, if set to True, then each command sent to
239 239 the interpreter will be executed in a separated thread allowing,
240 240 for example, breaking a long running commands.
241 241 Disallowing it, permits better compatibilty with instance that is embedding
242 242 IPython instance.
243 243
244 244 @param state: Sets threading state
245 245 @type bool
246 246 """
247 247 self._threading = state
248 248
249 249 def get_doc_text(self):
250 250 """
251 251 Returns the output of the processing that need to be paged (if any)
252 252
253 253 @return: The std output string.
254 254 @rtype: string
255 255 """
256 256 return self._doc_text
257 257
258 258 def get_help_text(self):
259 259 """
260 260 Returns the output of the processing that need to be paged via help pager(if any)
261 261
262 262 @return: The std output string.
263 263 @rtype: string
264 264 """
265 265 return self._help_text
266 266
267 267 def get_banner(self):
268 268 """
269 269 Returns the IPython banner for useful info on IPython instance
270 270
271 271 @return: The banner string.
272 272 @rtype: string
273 273 """
274 274 return self._IP.BANNER
275 275
276 276 def get_prompt_count(self):
277 277 """
278 278 Returns the prompt number.
279 279 Each time a user execute a line in the IPython shell the prompt count is increased
280 280
281 281 @return: The prompt number
282 282 @rtype: int
283 283 """
284 284 return self._IP.outputcache.prompt_count
285 285
286 286 def get_prompt(self):
287 287 """
288 288 Returns current prompt inside IPython instance
289 289 (Can be In [...]: ot ...:)
290 290
291 291 @return: The current prompt.
292 292 @rtype: string
293 293 """
294 294 return self._prompt
295 295
296 296 def get_indentation(self):
297 297 """
298 298 Returns the current indentation level
299 299 Usefull to put the caret at the good start position if we want to do autoindentation.
300 300
301 301 @return: The indentation level.
302 302 @rtype: int
303 303 """
304 304 return self._IP.indent_current_nsp
305 305
306 306 def update_namespace(self, ns_dict):
307 307 '''
308 308 Add the current dictionary to the shell namespace.
309 309
310 310 @param ns_dict: A dictionary of symbol-values.
311 311 @type ns_dict: dictionary
312 312 '''
313 313 self._IP.user_ns.update(ns_dict)
314 314
315 315 def complete(self, line):
316 316 '''
317 317 Returns an auto completed line and/or posibilities for completion.
318 318
319 319 @param line: Given line so far.
320 320 @type line: string
321 321
322 322 @return: Line completed as for as possible,
323 323 and possible further completions.
324 324 @rtype: tuple
325 325 '''
326 326 split_line = self._complete_sep.split(line)
327 327 possibilities = self._IP.complete(split_line[-1])
328 328 if possibilities:
329 329
330 330 def _common_prefix(str1, str2):
331 331 '''
332 332 Reduction function. returns common prefix of two given strings.
333 333
334 334 @param str1: First string.
335 335 @type str1: string
336 336 @param str2: Second string
337 337 @type str2: string
338 338
339 339 @return: Common prefix to both strings.
340 340 @rtype: string
341 341 '''
342 342 for i in range(len(str1)):
343 343 if not str2.startswith(str1[:i+1]):
344 344 return str1[:i]
345 345 return str1
346 346 common_prefix = reduce(_common_prefix, possibilities)
347 347 completed = line[:-len(split_line[-1])]+common_prefix
348 348 else:
349 349 completed = line
350 350 return completed, possibilities
351 351
352 352 def history_back(self):
353 353 '''
354 354 Provides one history command back.
355 355
356 356 @return: The command string.
357 357 @rtype: string
358 358 '''
359 359 history = ''
360 360 #the below while loop is used to suppress empty history lines
361 361 while((history == '' or history == '\n') and self._history_level >0):
362 362 if self._history_level >= 1:
363 363 self._history_level -= 1
364 364 history = self._get_history()
365 365 return history
366 366
367 367 def history_forward(self):
368 368 '''
369 369 Provides one history command forward.
370 370
371 371 @return: The command string.
372 372 @rtype: string
373 373 '''
374 374 history = ''
375 375 #the below while loop is used to suppress empty history lines
376 376 while((history == '' or history == '\n') \
377 377 and self._history_level <= self._get_history_max_index()):
378 378 if self._history_level < self._get_history_max_index():
379 379 self._history_level += 1
380 380 history = self._get_history()
381 381 else:
382 382 if self._history_level == self._get_history_max_index():
383 383 history = self._get_history()
384 384 self._history_level += 1
385 385 else:
386 386 history = ''
387 387 return history
388 388
389 389 def init_history_index(self):
390 390 '''
391 391 set history to last command entered
392 392 '''
393 393 self._history_level = self._get_history_max_index()+1
394 394
395 395 #----------------------- IPython PRIVATE management section --------------
396 396 def _after_execute(self):
397 397 '''
398 398 Can be redefined to generate post event after excution is done
399 399 '''
400 400 pass
401 401
402 402 def _ask_exit(self):
403 403 '''
404 404 Can be redefined to generate post event to exit the Ipython shell
405 405 '''
406 406 pass
407 407
408 408 def _get_history_max_index(self):
409 409 '''
410 410 returns the max length of the history buffer
411 411
412 412 @return: history length
413 413 @rtype: int
414 414 '''
415 415 return len(self._IP.input_hist_raw)-1
416 416
417 417 def _get_history(self):
418 418 '''
419 419 Get's the command string of the current history level.
420 420
421 421 @return: Historic command stri
422 422 @rtype: string
423 423 '''
424 424 rv = self._IP.input_hist_raw[self._history_level].strip('\n')
425 425 return rv
426 426
427 427 def _pager_help(self, text):
428 428 '''
429 429 This function is used as a callback replacment to IPython help pager function
430 430
431 431 It puts the 'text' value inside the self._help_text string that can be retrived via
432 432 get_help_text function.
433 433 '''
434 434 if self._help_text == None:
435 435 self._help_text = text
436 436 else:
437 437 self._help_text += text
438 438
439 439 def _pager(self, IP, text):
440 440 '''
441 441 This function is used as a callback replacment to IPython pager function
442 442
443 443 It puts the 'text' value inside the self._doc_text string that can be retrived via
444 444 get_doc_text function.
445 445 '''
446 446 self._doc_text = text
447 447
448 448 def _raw_input_original(self, prompt=''):
449 449 '''
450 450 Custom raw_input() replacement. Get's current line from console buffer.
451 451
452 452 @param prompt: Prompt to print. Here for compatability as replacement.
453 453 @type prompt: string
454 454
455 455 @return: The current command line text.
456 456 @rtype: string
457 457 '''
458 458 return self._line_to_execute
459 459
460 460 def _raw_input(self, prompt=''):
461 461 """ A replacement from python's raw_input.
462 462 """
463 463 raise NotImplementedError
464 464
465 465 def _execute(self):
466 466 '''
467 467 Executes the current line provided by the shell object.
468 468 '''
469 469
470 470 orig_stdout = sys.stdout
471 471 sys.stdout = IPython.Shell.Term.cout
472 472 #self.sys_displayhook_ori = sys.displayhook
473 473 #sys.displayhook = self.displayhook
474 474
475 475 try:
476 476 line = self._IP.raw_input(None, self._iter_more)
477 477 if self._IP.autoindent:
478 478 self._IP.readline_startup_hook(None)
479 479
480 480 except KeyboardInterrupt:
481 481 self._IP.write('\nKeyboardInterrupt\n')
482 482 self._IP.resetbuffer()
483 483 # keep cache in sync with the prompt counter:
484 484 self._IP.outputcache.prompt_count -= 1
485 485
486 486 if self._IP.autoindent:
487 487 self._IP.indent_current_nsp = 0
488 488 self._iter_more = 0
489 489 except:
490 490 self._IP.showtraceback()
491 491 else:
492 492 self._IP.write(str(self._IP.outputcache.prompt_out).strip())
493 493 self._iter_more = self._IP.push(line)
494 494 if (self._IP.SyntaxTB.last_syntax_error and \
495 495 self._IP.rc.autoedit_syntax):
496 496 self._IP.edit_syntax_error()
497 497 if self._iter_more:
498 498 self._prompt = str(self._IP.outputcache.prompt2).strip()
499 499 if self._IP.autoindent:
500 500 self._IP.readline_startup_hook(self._IP.pre_readline)
501 501 else:
502 502 self._prompt = str(self._IP.outputcache.prompt1).strip()
503 503 self._IP.indent_current_nsp = 0 #we set indentation to 0
504 504
505 505 sys.stdout = orig_stdout
506 506 #sys.displayhook = self.sys_displayhook_ori
507 507
508 508 def _shell(self, ip, cmd):
509 509 '''
510 510 Replacement method to allow shell commands without them blocking.
511 511
512 512 @param ip: Ipython instance, same as self._IP
513 513 @type cmd: Ipython instance
514 514 @param cmd: Shell command to execute.
515 515 @type cmd: string
516 516 '''
517 517 stdin, stdout = os.popen4(cmd)
518 518 result = stdout.read().decode('cp437').\
519 519 encode(locale.getpreferredencoding())
520 520 #we use print command because the shell command is called
521 521 #inside IPython instance and thus is redirected to thread cout
522 522 #"\x01\x1b[1;36m\x02" <-- add colour to the text...
523 523 print "\x01\x1b[1;36m\x02"+result
524 524 stdout.close()
525 525 stdin.close()
@@ -1,942 +1,942 b''
1 1 #!/usr/bin/python
2 2 # -*- coding: utf-8 -*-
3 3 '''
4 4 Provides IPython WX console widgets.
5 5
6 6 @author: Laurent Dufrechou
7 7 laurent.dufrechou _at_ gmail.com
8 8 This WX widget is based on the original work of Eitan Isaacson
9 9 that provided the console for the GTK toolkit.
10 10
11 11 Original work from:
12 12 @author: Eitan Isaacson
13 13 @organization: IBM Corporation
14 14 @copyright: Copyright (c) 2007 IBM Corporation
15 15 @license: BSD
16 16
17 17 All rights reserved. This program and the accompanying materials are made
18 18 available under the terms of the BSD which accompanies this distribution, and
19 19 is available at U{http://www.opensource.org/licenses/bsd-license.php}
20 20 '''
21 21
22 22 __version__ = 0.9
23 23 __author__ = "Laurent Dufrechou"
24 24 __email__ = "laurent.dufrechou _at_ gmail.com"
25 25 __license__ = "BSD"
26 26
27 27 import wx
28 28 import wx.stc as stc
29 29
30 30 import re
31 31 from StringIO import StringIO
32 32
33 33 import sys
34 34 import codecs
35 35 import locale
36 36 import time
37 37
38 38 for enc in (locale.getpreferredencoding(),
39 39 sys.getfilesystemencoding(),
40 40 sys.getdefaultencoding()):
41 41 try:
42 42 codecs.lookup(enc)
43 43 ENCODING = enc
44 44 break
45 45 except LookupError:
46 46 pass
47 47 else:
48 48 ENCODING = 'utf-8'
49 49
50 50 from ipshell_nonblocking import NonBlockingIPShell
51 51
52 52 class WxNonBlockingIPShell(NonBlockingIPShell):
53 53 '''
54 54 An NonBlockingIPShell Thread that is WX dependent.
55 55 '''
56 56 def __init__(self, parent,
57 57 argv=[],user_ns={},user_global_ns=None,
58 58 cin=None, cout=None, cerr=None,
59 59 ask_exit_handler=None):
60 60
61 61 NonBlockingIPShell.__init__(self, argv, user_ns, user_global_ns,
62 62 cin, cout, cerr,
63 63 ask_exit_handler)
64 64
65 65 self.parent = parent
66 66
67 67 self.ask_exit_callback = ask_exit_handler
68 68 self._IP.exit = self._ask_exit
69 69
70 70 def addGUIShortcut(self, text, func):
71 71 wx.CallAfter(self.parent.add_button_handler,
72 72 button_info={ 'text':text,
73 73 'func':self.parent.doExecuteLine(func)})
74 74
75 75 def _raw_input(self, prompt=''):
76 76 """ A replacement from python's raw_input.
77 77 """
78 78 self.answer = None
79 if(self._threading == True):
80 wx.CallAfter(self._yesNoBox, prompt)
81 while self.answer is None:
82 time.sleep(.1)
79 if(self._threading == True):
80 wx.CallAfter(self._yesNoBox, prompt)
81 while self.answer is None:
82 time.sleep(.1)
83 83 else:
84 self._yesNoBox(prompt)
84 self._yesNoBox(prompt)
85 85 return self.answer
86 86
87 87 def _yesNoBox(self, prompt):
88 88 """ yes/no box managed with wx.CallAfter jsut in case caler is executed in a thread"""
89 89 dlg = wx.TextEntryDialog(
90 90 self.parent, prompt,
91 91 'Input requested', 'Python')
92 92 dlg.SetValue("")
93 93
94 94 answer = ''
95 95 if dlg.ShowModal() == wx.ID_OK:
96 96 answer = dlg.GetValue()
97 97
98 98 dlg.Destroy()
99 99 self.answer = answer
100 100
101 101 def _ask_exit(self):
102 102 wx.CallAfter(self.ask_exit_callback, ())
103 103
104 104 def _after_execute(self):
105 105 wx.CallAfter(self.parent.evtStateExecuteDone, ())
106 106
107 107
108 108 class WxConsoleView(stc.StyledTextCtrl):
109 109 '''
110 110 Specialized styled text control view for console-like workflow.
111 111 We use here a scintilla frontend thus it can be reused in any GUI that
112 112 supports scintilla with less work.
113 113
114 114 @cvar ANSI_COLORS_BLACK: Mapping of terminal colors to X11 names.
115 115 (with Black background)
116 116 @type ANSI_COLORS_BLACK: dictionary
117 117
118 118 @cvar ANSI_COLORS_WHITE: Mapping of terminal colors to X11 names.
119 119 (with White background)
120 120 @type ANSI_COLORS_WHITE: dictionary
121 121
122 122 @ivar color_pat: Regex of terminal color pattern
123 123 @type color_pat: _sre.SRE_Pattern
124 124 '''
125 125 ANSI_STYLES_BLACK = {'0;30': [0, 'WHITE'], '0;31': [1, 'RED'],
126 126 '0;32': [2, 'GREEN'], '0;33': [3, 'BROWN'],
127 127 '0;34': [4, 'BLUE'], '0;35': [5, 'PURPLE'],
128 128 '0;36': [6, 'CYAN'], '0;37': [7, 'LIGHT GREY'],
129 129 '1;30': [8, 'DARK GREY'], '1;31': [9, 'RED'],
130 130 '1;32': [10, 'SEA GREEN'], '1;33': [11, 'YELLOW'],
131 131 '1;34': [12, 'LIGHT BLUE'], '1;35':
132 132 [13, 'MEDIUM VIOLET RED'],
133 133 '1;36': [14, 'LIGHT STEEL BLUE'], '1;37': [15, 'YELLOW']}
134 134
135 135 ANSI_STYLES_WHITE = {'0;30': [0, 'BLACK'], '0;31': [1, 'RED'],
136 136 '0;32': [2, 'GREEN'], '0;33': [3, 'BROWN'],
137 137 '0;34': [4, 'BLUE'], '0;35': [5, 'PURPLE'],
138 138 '0;36': [6, 'CYAN'], '0;37': [7, 'LIGHT GREY'],
139 139 '1;30': [8, 'DARK GREY'], '1;31': [9, 'RED'],
140 140 '1;32': [10, 'SEA GREEN'], '1;33': [11, 'YELLOW'],
141 141 '1;34': [12, 'LIGHT BLUE'], '1;35':
142 142 [13, 'MEDIUM VIOLET RED'],
143 143 '1;36': [14, 'LIGHT STEEL BLUE'], '1;37': [15, 'YELLOW']}
144 144
145 145 def __init__(self, parent, prompt, intro="", background_color="BLACK",
146 146 pos=wx.DefaultPosition, ID = -1, size=wx.DefaultSize,
147 147 style=0, autocomplete_mode = 'IPYTHON'):
148 148 '''
149 149 Initialize console view.
150 150
151 151 @param parent: Parent widget
152 152 @param prompt: User specified prompt
153 153 @type intro: string
154 154 @param intro: User specified startup introduction string
155 155 @type intro: string
156 156 @param background_color: Can be BLACK or WHITE
157 157 @type background_color: string
158 158 @param other: init param of styledTextControl (can be used as-is)
159 159 @param autocomplete_mode: Can be 'IPYTHON' or 'STC'
160 160 'IPYTHON' show autocompletion the ipython way
161 161 'STC" show it scintilla text control way
162 162 '''
163 163 stc.StyledTextCtrl.__init__(self, parent, ID, pos, size, style)
164 164
165 165 ####### Scintilla configuration ###################################
166 166
167 167 # Ctrl + B or Ctrl + N can be used to zoomin/zoomout the text inside
168 168 # the widget
169 169 self.CmdKeyAssign(ord('B'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
170 170 self.CmdKeyAssign(ord('N'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
171 171
172 172 #We draw a line at position 80
173 173 self.SetEdgeMode(stc.STC_EDGE_LINE)
174 174 self.SetEdgeColumn(80)
175 175 self.SetEdgeColour(wx.LIGHT_GREY)
176 176
177 177 #self.SetViewWhiteSpace(True)
178 178 #self.SetViewEOL(True)
179 179 self.SetEOLMode(stc.STC_EOL_CRLF)
180 180 #self.SetWrapMode(stc.STC_WRAP_CHAR)
181 181 #self.SetWrapMode(stc.STC_WRAP_WORD)
182 182 self.SetBufferedDraw(True)
183 183 #self.SetUseAntiAliasing(True)
184 184 self.SetLayoutCache(stc.STC_CACHE_PAGE)
185 185 self.SetUndoCollection(False)
186 186 self.SetUseTabs(True)
187 187 self.SetIndent(4)
188 188 self.SetTabWidth(4)
189 189
190 190 self.EnsureCaretVisible()
191 191
192 192 self.SetMargins(3, 3) #text is moved away from border with 3px
193 193 # Suppressing Scintilla margins
194 194 self.SetMarginWidth(0, 0)
195 195 self.SetMarginWidth(1, 0)
196 196 self.SetMarginWidth(2, 0)
197 197
198 198 self.background_color = background_color
199 199 self.buildStyles()
200 200
201 201 self.indent = 0
202 202 self.prompt_count = 0
203 203 self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?')
204 204
205 205 self.write(intro)
206 206 self.setPrompt(prompt)
207 207 self.showPrompt()
208 208
209 209 self.autocomplete_mode = autocomplete_mode
210 210
211 211 self.Bind(wx.EVT_KEY_DOWN, self._onKeypress)
212 212
213 213 def buildStyles(self):
214 214 #we define platform specific fonts
215 215 if wx.Platform == '__WXMSW__':
216 216 faces = { 'times': 'Times New Roman',
217 217 'mono' : 'Courier New',
218 218 'helv' : 'Arial',
219 219 'other': 'Comic Sans MS',
220 220 'size' : 10,
221 221 'size2': 8,
222 222 }
223 223 elif wx.Platform == '__WXMAC__':
224 224 faces = { 'times': 'Times New Roman',
225 225 'mono' : 'Monaco',
226 226 'helv' : 'Arial',
227 227 'other': 'Comic Sans MS',
228 228 'size' : 10,
229 229 'size2': 8,
230 230 }
231 231 else:
232 232 faces = { 'times': 'Times',
233 233 'mono' : 'Courier',
234 234 'helv' : 'Helvetica',
235 235 'other': 'new century schoolbook',
236 236 'size' : 10,
237 237 'size2': 8,
238 238 }
239 239
240 240 # make some styles
241 241 if self.background_color != "BLACK":
242 242 self.background_color = "WHITE"
243 243 self.SetCaretForeground("BLACK")
244 244 self.ANSI_STYLES = self.ANSI_STYLES_WHITE
245 245 else:
246 246 self.SetCaretForeground("WHITE")
247 247 self.ANSI_STYLES = self.ANSI_STYLES_BLACK
248 248
249 249 self.StyleSetSpec(stc.STC_STYLE_DEFAULT,
250 250 "fore:%s,back:%s,size:%d,face:%s"
251 251 % (self.ANSI_STYLES['0;30'][1],
252 252 self.background_color,
253 253 faces['size'], faces['mono']))
254 254 self.StyleClearAll()
255 255 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT,
256 256 "fore:#FF0000,back:#0000FF,bold")
257 257 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD,
258 258 "fore:#000000,back:#FF0000,bold")
259 259
260 260 for style in self.ANSI_STYLES.values():
261 261 self.StyleSetSpec(style[0], "bold,fore:%s" % style[1])
262 262
263 263 #######################################################################
264 264
265 265 def setBackgroundColor(self, color):
266 266 self.background_color = color
267 267 self.buildStyles()
268 268
269 269 def getBackgroundColor(self, color):
270 270 return self.background_color
271 271
272 272 def asyncWrite(self, text):
273 273 '''
274 274 Write given text to buffer in an asynchroneous way.
275 275 It is used from another thread to be able to acces the GUI.
276 276 @param text: Text to append
277 277 @type text: string
278 278 '''
279 279 try:
280 280 wx.MutexGuiEnter()
281 281
282 282 #be sure not to be interrutpted before the MutexGuiLeave!
283 283 self.write(text)
284 284
285 285 except KeyboardInterrupt:
286 286 wx.MutexGuiLeave()
287 287 raise KeyboardInterrupt
288 288 wx.MutexGuiLeave()
289 289
290 290
291 291 def write(self, text):
292 292 '''
293 293 Write given text to buffer.
294 294
295 295 @param text: Text to append.
296 296 @type text: string
297 297 '''
298 298 segments = self.color_pat.split(text)
299 299 segment = segments.pop(0)
300 300 self.StartStyling(self.getCurrentLineEnd(), 0xFF)
301 301 self.AppendText(segment)
302 302
303 303 if segments:
304 304 ansi_tags = self.color_pat.findall(text)
305 305
306 306 for tag in ansi_tags:
307 307 i = segments.index(tag)
308 308 self.StartStyling(self.getCurrentLineEnd(), 0xFF)
309 309 self.AppendText(segments[i+1])
310 310
311 311 if tag != '0':
312 312 self.SetStyling(len(segments[i+1]), self.ANSI_STYLES[tag][0])
313 313
314 314 segments.pop(i)
315 315
316 316 self.moveCursor(self.getCurrentLineEnd())
317 317
318 318 def getPromptLen(self):
319 319 '''
320 320 Return the length of current prompt
321 321 '''
322 322 return len(str(self.prompt_count)) + 7
323 323
324 324 def setPrompt(self, prompt):
325 325 self.prompt = prompt
326 326
327 327 def setIndentation(self, indentation):
328 328 self.indent = indentation
329 329
330 330 def setPromptCount(self, count):
331 331 self.prompt_count = count
332 332
333 333 def showPrompt(self):
334 334 '''
335 335 Prints prompt at start of line.
336 336
337 337 @param prompt: Prompt to print.
338 338 @type prompt: string
339 339 '''
340 340 self.write(self.prompt)
341 341 #now we update the position of end of prompt
342 342 self.current_start = self.getCurrentLineEnd()
343 343
344 344 autoindent = self.indent*' '
345 345 autoindent = autoindent.replace(' ','\t')
346 346 self.write(autoindent)
347 347
348 348 def changeLine(self, text):
349 349 '''
350 350 Replace currently entered command line with given text.
351 351
352 352 @param text: Text to use as replacement.
353 353 @type text: string
354 354 '''
355 355 self.SetSelection(self.getCurrentPromptStart(), self.getCurrentLineEnd())
356 356 self.ReplaceSelection(text)
357 357 self.moveCursor(self.getCurrentLineEnd())
358 358
359 359 def getCurrentPromptStart(self):
360 360 return self.current_start
361 361
362 362 def getCurrentLineStart(self):
363 363 return self.GotoLine(self.LineFromPosition(self.GetCurrentPos()))
364 364
365 365 def getCurrentLineEnd(self):
366 366 return self.GetLength()
367 367
368 368 def getCurrentLine(self):
369 369 '''
370 370 Get text in current command line.
371 371
372 372 @return: Text of current command line.
373 373 @rtype: string
374 374 '''
375 375 return self.GetTextRange(self.getCurrentPromptStart(),
376 376 self.getCurrentLineEnd())
377 377
378 378 def moveCursorOnNewValidKey(self):
379 379 #If cursor is at wrong position put it at last line...
380 380 if self.GetCurrentPos() < self.getCurrentPromptStart():
381 381 self.GotoPos(self.getCurrentPromptStart())
382 382
383 383 def removeFromTo(self, from_pos, to_pos):
384 384 if from_pos < to_pos:
385 385 self.SetSelection(from_pos, to_pos)
386 386 self.DeleteBack()
387 387
388 388 def removeCurrentLine(self):
389 389 self.LineDelete()
390 390
391 391 def moveCursor(self, position):
392 392 self.GotoPos(position)
393 393
394 394 def getCursorPos(self):
395 395 return self.GetCurrentPos()
396 396
397 397 def selectFromTo(self, from_pos, to_pos):
398 398 self.SetSelectionStart(from_pos)
399 399 self.SetSelectionEnd(to_pos)
400 400
401 401 def writeHistory(self, history):
402 402 self.removeFromTo(self.getCurrentPromptStart(), self.getCurrentLineEnd())
403 403 self.changeLine(history)
404 404
405 405 def setCompletionMethod(self, completion):
406 406 if completion in ['IPYTHON', 'STC']:
407 407 self.autocomplete_mode = completion
408 408 else:
409 409 raise AttributeError
410 410
411 411 def getCompletionMethod(self, completion):
412 412 return self.autocomplete_mode
413 413
414 414 def writeCompletion(self, possibilities):
415 415 if self.autocomplete_mode == 'IPYTHON':
416 416 max_len = len(max(possibilities, key=len))
417 417 max_symbol = ' '*max_len
418 418
419 419 #now we check how much symbol we can put on a line...
420 420 test_buffer = max_symbol + ' '*4
421 421
422 422 allowed_symbols = 80/len(test_buffer)
423 423 if allowed_symbols == 0:
424 424 allowed_symbols = 1
425 425
426 426 pos = 1
427 427 buf = ''
428 428 for symbol in possibilities:
429 429 #buf += symbol+'\n'#*spaces)
430 430 if pos < allowed_symbols:
431 431 spaces = max_len - len(symbol) + 4
432 432 buf += symbol+' '*spaces
433 433 pos += 1
434 434 else:
435 435 buf += symbol+'\n'
436 436 pos = 1
437 437 self.write(buf)
438 438 else:
439 439 possibilities.sort() # Python sorts are case sensitive
440 440 self.AutoCompSetIgnoreCase(False)
441 441 self.AutoCompSetAutoHide(False)
442 442 #let compute the length ot last word
443 443 splitter = [' ', '(', '[', '{','=']
444 444 last_word = self.getCurrentLine()
445 445 for breaker in splitter:
446 446 last_word = last_word.split(breaker)[-1]
447 447 self.AutoCompShow(len(last_word), " ".join(possibilities))
448 448
449 449 def _onKeypress(self, event, skip=True):
450 450 '''
451 451 Key press callback used for correcting behavior for console-like
452 452 interfaces. For example 'home' should go to prompt, not to begining of
453 453 line.
454 454
455 455 @param widget: Widget that key press accored in.
456 456 @type widget: gtk.Widget
457 457 @param event: Event object
458 458 @type event: gtk.gdk.Event
459 459
460 460 @return: Return True if event as been catched.
461 461 @rtype: boolean
462 462 '''
463 463 if not self.AutoCompActive():
464 464 if event.GetKeyCode() == wx.WXK_HOME:
465 465 if event.Modifiers == wx.MOD_NONE:
466 466 self.moveCursorOnNewValidKey()
467 467 self.moveCursor(self.getCurrentPromptStart())
468 468 return True
469 469 elif event.Modifiers == wx.MOD_SHIFT:
470 470 self.moveCursorOnNewValidKey()
471 471 self.selectFromTo(self.getCurrentPromptStart(), self.getCursorPos())
472 472 return True
473 473 else:
474 474 return False
475 475
476 476 elif event.GetKeyCode() == wx.WXK_LEFT:
477 477 if event.Modifiers == wx.MOD_NONE:
478 478 self.moveCursorOnNewValidKey()
479 479
480 480 self.moveCursor(self.getCursorPos()-1)
481 481 if self.getCursorPos() < self.getCurrentPromptStart():
482 482 self.moveCursor(self.getCurrentPromptStart())
483 483 return True
484 484
485 485 elif event.GetKeyCode() == wx.WXK_BACK:
486 486 self.moveCursorOnNewValidKey()
487 487 if self.getCursorPos() > self.getCurrentPromptStart():
488 488 event.Skip()
489 489 return True
490 490
491 491 if skip:
492 492 if event.GetKeyCode() not in [wx.WXK_PAGEUP, wx.WXK_PAGEDOWN]\
493 493 and event.Modifiers == wx.MOD_NONE:
494 494 self.moveCursorOnNewValidKey()
495 495
496 496 event.Skip()
497 497 return True
498 498 return False
499 499 else:
500 500 event.Skip()
501 501
502 502 def OnUpdateUI(self, evt):
503 503 # check for matching braces
504 504 braceAtCaret = -1
505 505 braceOpposite = -1
506 506 charBefore = None
507 507 caretPos = self.GetCurrentPos()
508 508
509 509 if caretPos > 0:
510 510 charBefore = self.GetCharAt(caretPos - 1)
511 511 styleBefore = self.GetStyleAt(caretPos - 1)
512 512
513 513 # check before
514 514 if charBefore and chr(charBefore) in "[]{}()" and styleBefore == stc.STC_P_OPERATOR:
515 515 braceAtCaret = caretPos - 1
516 516
517 517 # check after
518 518 if braceAtCaret < 0:
519 519 charAfter = self.GetCharAt(caretPos)
520 520 styleAfter = self.GetStyleAt(caretPos)
521 521
522 522 if charAfter and chr(charAfter) in "[]{}()" and styleAfter == stc.STC_P_OPERATOR:
523 523 braceAtCaret = caretPos
524 524
525 525 if braceAtCaret >= 0:
526 526 braceOpposite = self.BraceMatch(braceAtCaret)
527 527
528 528 if braceAtCaret != -1 and braceOpposite == -1:
529 529 self.BraceBadLight(braceAtCaret)
530 530 else:
531 531 self.BraceHighlight(braceAtCaret, braceOpposite)
532 532 #pt = self.PointFromPosition(braceOpposite)
533 533 #self.Refresh(True, wxRect(pt.x, pt.y, 5,5))
534 534 #print pt
535 535 #self.Refresh(False)
536 536
537 537 class IPShellWidget(wx.Panel):
538 538 '''
539 539 This is wx.Panel that embbed the IPython Thread and the wx.StyledTextControl
540 540 If you want to port this to any other GUI toolkit, just replace the
541 541 WxConsoleView by YOURGUIConsoleView and make YOURGUIIPythonView derivate
542 542 from whatever container you want. I've choosed to derivate from a wx.Panel
543 543 because it seems to be more useful
544 544 Any idea to make it more 'generic' welcomed.
545 545 '''
546 546
547 547 def __init__(self, parent, intro=None,
548 548 background_color="BLACK", add_button_handler=None,
549 549 wx_ip_shell=None, user_ns={},user_global_ns=None,
550 550 ):
551 551 '''
552 552 Initialize.
553 553 Instanciate an IPython thread.
554 554 Instanciate a WxConsoleView.
555 555 Redirect I/O to console.
556 556 '''
557 557 wx.Panel.__init__(self,parent,wx.ID_ANY)
558 558
559 559 self.parent = parent
560 560 ### IPython non blocking shell instanciation ###
561 561 self.cout = StringIO()
562 562 self.add_button_handler = add_button_handler
563 563
564 564 if wx_ip_shell is not None:
565 565 self.IP = wx_ip_shell
566 566 else:
567 567 self.IP = WxNonBlockingIPShell(self,
568 568 cout = self.cout, cerr = self.cout,
569 569 ask_exit_handler = self.askExitCallback)
570 570
571 571 ### IPython wx console view instanciation ###
572 572 #If user didn't defined an intro text, we create one for him
573 573 #If you really wnat an empty intro just call wxIPythonViewPanel
574 574 #with intro=''
575 575 if intro is None:
576 576 welcome_text = "Welcome to WxIPython Shell.\n\n"
577 577 welcome_text+= self.IP.get_banner()
578 578 welcome_text+= "!command -> Execute command in shell\n"
579 579 welcome_text+= "TAB -> Autocompletion\n"
580 580 else:
581 581 welcome_text = intro
582 582
583 583 self.text_ctrl = WxConsoleView(self,
584 584 self.IP.get_prompt(),
585 585 intro=welcome_text,
586 586 background_color=background_color)
587 587
588 588 option_text = wx.StaticText(self, -1, "Options:")
589 589 self.completion_option = wx.CheckBox(self, -1, "Scintilla Completion")
590 590 self.completion_option.SetToolTip(wx.ToolTip(
591 591 "Selects the completion type:\nEither Ipython default style or Scintilla one"))
592 592 #self.completion_option.SetValue(False)
593 593 self.background_option = wx.CheckBox(self, -1, "White Background")
594 594 self.background_option.SetToolTip(wx.ToolTip(
595 595 "Selects the back ground color: BLACK or WHITE"))
596 596 #self.background_option.SetValue(False)
597 597 self.threading_option = wx.CheckBox(self, -1, "Execute in thread")
598 598 self.threading_option.SetToolTip(wx.ToolTip(
599 599 "Use threading: infinite loop don't freeze the GUI and commands can be breaked\nNo threading: maximum compatibility"))
600 600 #self.threading_option.SetValue(False)
601 601
602 602 self.options={'completion':{'value':'IPYTHON',
603 603 'checkbox':self.completion_option,'STC':True,'IPYTHON':False,
604 604 'setfunc':self.text_ctrl.setCompletionMethod},
605 605 'background_color':{'value':'BLACK',
606 606 'checkbox':self.background_option,'WHITE':True,'BLACK':False,
607 607 'setfunc':self.text_ctrl.setBackgroundColor},
608 608 'threading':{'value':'True',
609 609 'checkbox':self.threading_option,'True':True,'False':False,
610 610 'setfunc':self.IP.set_threading},
611 611 }
612 612
613 613 #self.cout.write dEfault option is asynchroneous because default sate is threading ON
614 614 self.cout.write = self.text_ctrl.asyncWrite
615 615 #we reloard options
616 616 self.reloadOptions(self.options)
617 617
618 618 self.text_ctrl.Bind(wx.EVT_KEY_DOWN, self.keyPress)
619 619 self.completion_option.Bind(wx.EVT_CHECKBOX, self.evtCheckOptionCompletion)
620 620 self.background_option.Bind(wx.EVT_CHECKBOX, self.evtCheckOptionBackgroundColor)
621 621 self.threading_option.Bind(wx.EVT_CHECKBOX, self.evtCheckOptionThreading)
622 622
623 623 ### making the layout of the panel ###
624 624 sizer = wx.BoxSizer(wx.VERTICAL)
625 625 sizer.Add(self.text_ctrl, 1, wx.EXPAND)
626 626 option_sizer = wx.BoxSizer(wx.HORIZONTAL)
627 627 sizer.Add(option_sizer, 0)
628 628 option_sizer.AddMany([(10, 20),
629 629 (option_text, 0, wx.ALIGN_CENTER_VERTICAL),
630 630 (5, 5),
631 631 (self.completion_option, 0, wx.ALIGN_CENTER_VERTICAL),
632 632 (8, 8),
633 633 (self.background_option, 0, wx.ALIGN_CENTER_VERTICAL),
634 634 (8, 8),
635 635 (self.threading_option, 0, wx.ALIGN_CENTER_VERTICAL)
636 636 ])
637 637 self.SetAutoLayout(True)
638 638 sizer.Fit(self)
639 639 sizer.SetSizeHints(self)
640 640 self.SetSizer(sizer)
641 641 #and we focus on the widget :)
642 642 self.SetFocus()
643 643
644 644 #widget state management (for key handling different cases)
645 645 self.setCurrentState('IDLE')
646 646 self.pager_state = 'DONE'
647 647 self.raw_input_current_line = 0
648 648
649 649 def askExitCallback(self, event):
650 650 self.askExitHandler(event)
651 651
652 652 #---------------------- IPython Thread Management ------------------------
653 653 def stateDoExecuteLine(self):
654 654 lines=self.text_ctrl.getCurrentLine()
655 655 self.text_ctrl.write('\n')
656 656 lines_to_execute = lines.replace('\t',' '*4)
657 657 lines_to_execute = lines_to_execute.replace('\r','')
658 658 self.IP.do_execute(lines_to_execute.encode(ENCODING))
659 659 self.updateHistoryTracker(lines)
660 660 if(self.text_ctrl.getCursorPos()!=0):
661 661 self.text_ctrl.removeCurrentLine()
662 662 self.setCurrentState('WAIT_END_OF_EXECUTION')
663 663
664 664 def evtStateExecuteDone(self,evt):
665 665 self.doc = self.IP.get_doc_text()
666 666 self.help = self.IP.get_help_text()
667 667 if self.doc:
668 668 self.pager_lines = self.doc[7:].split('\n')
669 669 self.pager_state = 'INIT'
670 670 self.setCurrentState('SHOW_DOC')
671 671 self.pager(self.doc)
672 672 elif self.help:
673 673 self.pager_lines = self.help.split('\n')
674 674 self.pager_state = 'INIT'
675 675 self.setCurrentState('SHOW_DOC')
676 676 self.pager(self.help)
677 677 else:
678 678 if(self.text_ctrl.getCursorPos()!=0):
679 679 self.text_ctrl.removeCurrentLine()
680 680 self.stateShowPrompt()
681 681
682 682 def stateShowPrompt(self):
683 683 self.setCurrentState('SHOW_PROMPT')
684 684 self.text_ctrl.setPrompt(self.IP.get_prompt())
685 685 self.text_ctrl.setIndentation(self.IP.get_indentation())
686 686 self.text_ctrl.setPromptCount(self.IP.get_prompt_count())
687 687 self.text_ctrl.showPrompt()
688 688 self.IP.init_history_index()
689 689 self.setCurrentState('IDLE')
690 690
691 691 def setCurrentState(self, state):
692 692 self.cur_state = state
693 693 self.updateStatusTracker(self.cur_state)
694 694
695 695 def pager(self,text):
696 696
697 697 if self.pager_state == 'INIT':
698 698 #print >>sys.__stdout__,"PAGER state:",self.pager_state
699 699 self.pager_nb_lines = len(self.pager_lines)
700 700 self.pager_index = 0
701 701 self.pager_do_remove = False
702 702 self.text_ctrl.write('\n')
703 703 self.pager_state = 'PROCESS_LINES'
704 704
705 705 if self.pager_state == 'PROCESS_LINES':
706 706 #print >>sys.__stdout__,"PAGER state:",self.pager_state
707 707 if self.pager_do_remove == True:
708 708 self.text_ctrl.removeCurrentLine()
709 709 self.pager_do_remove = False
710 710
711 711 if self.pager_nb_lines > 10:
712 712 #print >>sys.__stdout__,"PAGER processing 10 lines"
713 713 if self.pager_index > 0:
714 714 self.text_ctrl.write(">\x01\x1b[1;36m\x02"+self.pager_lines[self.pager_index]+'\n')
715 715 else:
716 716 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+self.pager_lines[self.pager_index]+'\n')
717 717
718 718 for line in self.pager_lines[self.pager_index+1:self.pager_index+9]:
719 719 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+line+'\n')
720 720 self.pager_index += 10
721 721 self.pager_nb_lines -= 10
722 722 self.text_ctrl.write("--- Push Enter to continue or 'Q' to quit---")
723 723 self.pager_do_remove = True
724 724 self.pager_state = 'WAITING'
725 725 return
726 726 else:
727 727 #print >>sys.__stdout__,"PAGER processing last lines"
728 728 if self.pager_nb_lines > 0:
729 729 if self.pager_index > 0:
730 730 self.text_ctrl.write(">\x01\x1b[1;36m\x02"+self.pager_lines[self.pager_index]+'\n')
731 731 else:
732 732 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+self.pager_lines[self.pager_index]+'\n')
733 733
734 734 self.pager_index += 1
735 735 self.pager_nb_lines -= 1
736 736 if self.pager_nb_lines > 0:
737 737 for line in self.pager_lines[self.pager_index:]:
738 738 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+line+'\n')
739 739 self.pager_nb_lines = 0
740 740 self.pager_state = 'DONE'
741 741 self.stateShowPrompt()
742 742
743 743 #------------------------ Key Handler ------------------------------------
744 744 def keyPress(self, event):
745 745 '''
746 746 Key press callback with plenty of shell goodness, like history,
747 747 autocompletions, etc.
748 748 '''
749 749 if event.GetKeyCode() == ord('C'):
750 750 if event.Modifiers == wx.MOD_CONTROL or event.Modifiers == wx.MOD_ALT:
751 751 if self.cur_state == 'WAIT_END_OF_EXECUTION':
752 752 #we raise an exception inside the IPython thread container
753 753 self.IP.ce.raise_exc(KeyboardInterrupt)
754 754 return
755 755
756 756 #let this before 'wx.WXK_RETURN' because we have to put 'IDLE'
757 757 #mode if AutoComp has been set as inactive
758 758 if self.cur_state == 'COMPLETING':
759 759 if not self.text_ctrl.AutoCompActive():
760 760 self.cur_state = 'IDLE'
761 761 else:
762 762 event.Skip()
763 763
764 764 if event.KeyCode == wx.WXK_RETURN:
765 765 if self.cur_state == 'IDLE':
766 766 #we change the state ot the state machine
767 767 self.setCurrentState('DO_EXECUTE_LINE')
768 768 self.stateDoExecuteLine()
769 769 return
770 770
771 771 if self.pager_state == 'WAITING':
772 772 self.pager_state = 'PROCESS_LINES'
773 773 self.pager(self.doc)
774 774 return
775 775
776 776 if self.cur_state == 'WAITING_USER_INPUT':
777 777 line=self.text_ctrl.getCurrentLine()
778 778 self.text_ctrl.write('\n')
779 779 self.setCurrentState('WAIT_END_OF_EXECUTION')
780 780 return
781 781
782 782 if event.GetKeyCode() in [ord('q'),ord('Q')]:
783 783 if self.pager_state == 'WAITING':
784 784 self.pager_state = 'DONE'
785 785 self.text_ctrl.write('\n')
786 786 self.stateShowPrompt()
787 787 return
788 788
789 789 if self.cur_state == 'WAITING_USER_INPUT':
790 790 event.Skip()
791 791
792 792 if self.cur_state == 'IDLE':
793 793 if event.KeyCode == wx.WXK_UP:
794 794 history = self.IP.history_back()
795 795 self.text_ctrl.writeHistory(history)
796 796 return
797 797 if event.KeyCode == wx.WXK_DOWN:
798 798 history = self.IP.history_forward()
799 799 self.text_ctrl.writeHistory(history)
800 800 return
801 801 if event.KeyCode == wx.WXK_TAB:
802 802 #if line empty we disable tab completion
803 803 if not self.text_ctrl.getCurrentLine().strip():
804 804 self.text_ctrl.write('\t')
805 805 return
806 806 completed, possibilities = self.IP.complete(self.text_ctrl.getCurrentLine())
807 807 if len(possibilities) > 1:
808 808 if self.text_ctrl.autocomplete_mode == 'IPYTHON':
809 809 cur_slice = self.text_ctrl.getCurrentLine()
810 810 self.text_ctrl.write('\n')
811 811 self.text_ctrl.writeCompletion(possibilities)
812 812 self.text_ctrl.write('\n')
813 813
814 814 self.text_ctrl.showPrompt()
815 815 self.text_ctrl.write(cur_slice)
816 816 self.text_ctrl.changeLine(completed or cur_slice)
817 817 else:
818 818 self.cur_state = 'COMPLETING'
819 819 self.text_ctrl.writeCompletion(possibilities)
820 820 else:
821 821 self.text_ctrl.changeLine(completed or cur_slice)
822 822 return
823 823 event.Skip()
824 824
825 825 #------------------------ Option Section ---------------------------------
826 826 def evtCheckOptionCompletion(self, event):
827 827 if event.IsChecked():
828 828 self.options['completion']['value']='STC'
829 829 else:
830 830 self.options['completion']['value']='IPYTHON'
831 831 self.text_ctrl.setCompletionMethod(self.options['completion']['value'])
832 832 self.updateOptionTracker('completion',
833 833 self.options['completion']['value'])
834 834 self.text_ctrl.SetFocus()
835 835
836 836 def evtCheckOptionBackgroundColor(self, event):
837 837 if event.IsChecked():
838 838 self.options['background_color']['value']='WHITE'
839 839 else:
840 840 self.options['background_color']['value']='BLACK'
841 841 self.text_ctrl.setBackgroundColor(self.options['background_color']['value'])
842 842 self.updateOptionTracker('background_color',
843 843 self.options['background_color']['value'])
844 844 self.text_ctrl.SetFocus()
845 845
846 846 def evtCheckOptionThreading(self, event):
847 847 if event.IsChecked():
848 848 self.options['threading']['value']='True'
849 849 self.IP.set_threading(True)
850 850 self.cout.write = self.text_ctrl.asyncWrite
851 851 else:
852 852 self.options['threading']['value']='False'
853 853 self.IP.set_threading(False)
854 854 self.cout.write = self.text_ctrl.write
855 855 self.updateOptionTracker('threading',
856 856 self.options['threading']['value'])
857 857 self.text_ctrl.SetFocus()
858 858
859 859 def getOptions(self):
860 860 return self.options
861 861
862 862 def reloadOptions(self,options):
863 863 self.options = options
864 864 for key in self.options.keys():
865 865 value = self.options[key]['value']
866 866 self.options[key]['checkbox'].SetValue(self.options[key][value])
867 867 self.options[key]['setfunc'](value)
868 868
869 869 if self.options['threading']['value']=='True':
870 870 self.IP.set_threading(True)
871 871 self.cout.write = self.text_ctrl.asyncWrite
872 872 else:
873 873 self.IP.set_threading(False)
874 874 self.cout.write = self.text_ctrl.write
875 875
876 876 #------------------------ Hook Section -----------------------------------
877 877 def updateOptionTracker(self,name,value):
878 878 '''
879 879 Default history tracker (does nothing)
880 880 '''
881 881 pass
882 882
883 883 def setOptionTrackerHook(self,func):
884 884 '''
885 885 Define a new history tracker
886 886 '''
887 887 self.updateOptionTracker = func
888 888
889 889 def updateHistoryTracker(self,command_line):
890 890 '''
891 891 Default history tracker (does nothing)
892 892 '''
893 893 pass
894 894
895 895 def setHistoryTrackerHook(self,func):
896 896 '''
897 897 Define a new history tracker
898 898 '''
899 899 self.updateHistoryTracker = func
900 900
901 901 def updateStatusTracker(self,status):
902 902 '''
903 903 Default status tracker (does nothing)
904 904 '''
905 905 pass
906 906
907 907 def setStatusTrackerHook(self,func):
908 908 '''
909 909 Define a new status tracker
910 910 '''
911 911 self.updateStatusTracker = func
912 912
913 913 def askExitHandler(self, event):
914 914 '''
915 915 Default exit handler
916 916 '''
917 917 self.text_ctrl.write('\nExit callback has not been set.')
918 918
919 919 def setAskExitHandler(self, func):
920 920 '''
921 921 Define an exit handler
922 922 '''
923 923 self.askExitHandler = func
924 924
925 925 if __name__ == '__main__':
926 926 # Some simple code to test the shell widget.
927 927 class MainWindow(wx.Frame):
928 928 def __init__(self, parent, id, title):
929 929 wx.Frame.__init__(self, parent, id, title, size=(300,250))
930 930 self._sizer = wx.BoxSizer(wx.VERTICAL)
931 931 self.shell = IPShellWidget(self)
932 932 self._sizer.Add(self.shell, 1, wx.EXPAND)
933 933 self.SetSizer(self._sizer)
934 934 self.SetAutoLayout(1)
935 935 self.Show(True)
936 936
937 937 app = wx.PySimpleApp()
938 938 frame = MainWindow(None, wx.ID_ANY, 'Ipython')
939 939 frame.SetSize((780, 460))
940 940 shell = frame.shell
941 941
942 942 app.MainLoop()
@@ -1,264 +1,264 b''
1 1 """hooks for IPython.
2 2
3 3 In Python, it is possible to overwrite any method of any object if you really
4 4 want to. But IPython exposes a few 'hooks', methods which are _designed_ to
5 5 be overwritten by users for customization purposes. This module defines the
6 6 default versions of all such hooks, which get used by IPython if not
7 7 overridden by the user.
8 8
9 9 hooks are simple functions, but they should be declared with 'self' as their
10 10 first argument, because when activated they are registered into IPython as
11 11 instance methods. The self argument will be the IPython running instance
12 12 itself, so hooks have full access to the entire IPython object.
13 13
14 14 If you wish to define a new hook and activate it, you need to put the
15 15 necessary code into a python file which can be either imported or execfile()'d
16 16 from within your ipythonrc configuration.
17 17
18 18 For example, suppose that you have a module called 'myiphooks' in your
19 19 PYTHONPATH, which contains the following definition:
20 20
21 21 import os
22 22 import IPython.ipapi
23 23 ip = IPython.ipapi.get()
24 24
25 25 def calljed(self,filename, linenum):
26 26 "My editor hook calls the jed editor directly."
27 27 print "Calling my own editor, jed ..."
28 28 if os.system('jed +%d %s' % (linenum,filename)) != 0:
29 29 raise ipapi.TryNext()
30 30
31 31 ip.set_hook('editor', calljed)
32 32
33 33 You can then enable the functionality by doing 'import myiphooks'
34 34 somewhere in your configuration files or ipython command line.
35 35 """
36 36
37 37 #*****************************************************************************
38 38 # Copyright (C) 2005 Fernando Perez. <fperez@colorado.edu>
39 39 #
40 40 # Distributed under the terms of the BSD License. The full license is in
41 41 # the file COPYING, distributed as part of this software.
42 42 #*****************************************************************************
43 43
44 44 from IPython import ipapi
45 45
46 46 import os,bisect
47 47 import sys
48 48 from genutils import Term,shell
49 49 from pprint import PrettyPrinter
50 50
51 51 # List here all the default hooks. For now it's just the editor functions
52 52 # but over time we'll move here all the public API for user-accessible things.
53 53 # vds: >>
54 54 __all__ = ['editor', 'fix_error_editor', 'synchronize_with_editor', 'result_display',
55 55 'input_prefilter', 'shutdown_hook', 'late_startup_hook',
56 56 'generate_prompt', 'generate_output_prompt','shell_hook',
57 57 'show_in_pager','pre_prompt_hook', 'pre_runcode_hook',
58 58 'clipboard_get']
59 59 # vds: <<
60 60
61 61 pformat = PrettyPrinter().pformat
62 62
63 63 def editor(self,filename, linenum=None):
64 64 """Open the default editor at the given filename and linenumber.
65 65
66 66 This is IPython's default editor hook, you can use it as an example to
67 67 write your own modified one. To set your own editor function as the
68 68 new editor hook, call ip.set_hook('editor',yourfunc)."""
69 69
70 70 # IPython configures a default editor at startup by reading $EDITOR from
71 71 # the environment, and falling back on vi (unix) or notepad (win32).
72 72 editor = self.rc.editor
73 73
74 74 # marker for at which line to open the file (for existing objects)
75 75 if linenum is None or editor=='notepad':
76 76 linemark = ''
77 77 else:
78 78 linemark = '+%d' % int(linenum)
79 79
80 80 # Enclose in quotes if necessary and legal
81 81 if ' ' in editor and os.path.isfile(editor) and editor[0] != '"':
82 82 editor = '"%s"' % editor
83 83
84 84 # Call the actual editor
85 85 if os.system('%s %s %s' % (editor,linemark,filename)) != 0:
86 86 raise ipapi.TryNext()
87 87
88 88 import tempfile
89 89 def fix_error_editor(self,filename,linenum,column,msg):
90 90 """Open the editor at the given filename, linenumber, column and
91 91 show an error message. This is used for correcting syntax errors.
92 92 The current implementation only has special support for the VIM editor,
93 93 and falls back on the 'editor' hook if VIM is not used.
94 94
95 95 Call ip.set_hook('fix_error_editor',youfunc) to use your own function,
96 96 """
97 97 def vim_quickfix_file():
98 98 t = tempfile.NamedTemporaryFile()
99 99 t.write('%s:%d:%d:%s\n' % (filename,linenum,column,msg))
100 100 t.flush()
101 101 return t
102 102 if os.path.basename(self.rc.editor) != 'vim':
103 103 self.hooks.editor(filename,linenum)
104 104 return
105 105 t = vim_quickfix_file()
106 106 try:
107 107 if os.system('vim --cmd "set errorformat=%f:%l:%c:%m" -q ' + t.name):
108 108 raise ipapi.TryNext()
109 109 finally:
110 110 t.close()
111 111
112 112 # vds: >>
113 113 def synchronize_with_editor(self, filename, linenum, column):
114 pass
114 pass
115 115 # vds: <<
116 116
117 117 class CommandChainDispatcher:
118 118 """ Dispatch calls to a chain of commands until some func can handle it
119 119
120 120 Usage: instantiate, execute "add" to add commands (with optional
121 121 priority), execute normally via f() calling mechanism.
122 122
123 123 """
124 124 def __init__(self,commands=None):
125 125 if commands is None:
126 126 self.chain = []
127 127 else:
128 128 self.chain = commands
129 129
130 130
131 131 def __call__(self,*args, **kw):
132 132 """ Command chain is called just like normal func.
133 133
134 134 This will call all funcs in chain with the same args as were given to this
135 135 function, and return the result of first func that didn't raise
136 136 TryNext """
137 137
138 138 for prio,cmd in self.chain:
139 139 #print "prio",prio,"cmd",cmd #dbg
140 140 try:
141 141 ret = cmd(*args, **kw)
142 142 return ret
143 143 except ipapi.TryNext, exc:
144 144 if exc.args or exc.kwargs:
145 145 args = exc.args
146 146 kw = exc.kwargs
147 147 # if no function will accept it, raise TryNext up to the caller
148 148 raise ipapi.TryNext
149 149
150 150 def __str__(self):
151 151 return str(self.chain)
152 152
153 153 def add(self, func, priority=0):
154 154 """ Add a func to the cmd chain with given priority """
155 155 bisect.insort(self.chain,(priority,func))
156 156
157 157 def __iter__(self):
158 158 """ Return all objects in chain.
159 159
160 160 Handy if the objects are not callable.
161 161 """
162 162 return iter(self.chain)
163 163
164 164 def result_display(self,arg):
165 165 """ Default display hook.
166 166
167 167 Called for displaying the result to the user.
168 168 """
169 169
170 170 if self.rc.pprint:
171 171 out = pformat(arg)
172 172 if '\n' in out:
173 173 # So that multi-line strings line up with the left column of
174 174 # the screen, instead of having the output prompt mess up
175 175 # their first line.
176 176 Term.cout.write('\n')
177 177 print >>Term.cout, out
178 178 else:
179 179 # By default, the interactive prompt uses repr() to display results,
180 180 # so we should honor this. Users who'd rather use a different
181 181 # mechanism can easily override this hook.
182 182 print >>Term.cout, repr(arg)
183 183 # the default display hook doesn't manipulate the value to put in history
184 184 return None
185 185
186 186 def input_prefilter(self,line):
187 187 """ Default input prefilter
188 188
189 189 This returns the line as unchanged, so that the interpreter
190 190 knows that nothing was done and proceeds with "classic" prefiltering
191 191 (%magics, !shell commands etc.).
192 192
193 193 Note that leading whitespace is not passed to this hook. Prefilter
194 194 can't alter indentation.
195 195
196 196 """
197 197 #print "attempt to rewrite",line #dbg
198 198 return line
199 199
200 200 def shutdown_hook(self):
201 201 """ default shutdown hook
202 202
203 203 Typically, shotdown hooks should raise TryNext so all shutdown ops are done
204 204 """
205 205
206 206 #print "default shutdown hook ok" # dbg
207 207 return
208 208
209 209 def late_startup_hook(self):
210 210 """ Executed after ipython has been constructed and configured
211 211
212 212 """
213 213 #print "default startup hook ok" # dbg
214 214
215 215 def generate_prompt(self, is_continuation):
216 216 """ calculate and return a string with the prompt to display """
217 217 ip = self.api
218 218 if is_continuation:
219 219 return str(ip.IP.outputcache.prompt2)
220 220 return str(ip.IP.outputcache.prompt1)
221 221
222 222 def generate_output_prompt(self):
223 223 ip = self.api
224 224 return str(ip.IP.outputcache.prompt_out)
225 225
226 226 def shell_hook(self,cmd):
227 227 """ Run system/shell command a'la os.system() """
228 228
229 229 shell(cmd, header=self.rc.system_header, verbose=self.rc.system_verbose)
230 230
231 231 def show_in_pager(self,s):
232 232 """ Run a string through pager """
233 233 # raising TryNext here will use the default paging functionality
234 234 raise ipapi.TryNext
235 235
236 236 def pre_prompt_hook(self):
237 237 """ Run before displaying the next prompt
238 238
239 239 Use this e.g. to display output from asynchronous operations (in order
240 240 to not mess up text entry)
241 241 """
242 242
243 243 return None
244 244
245 245 def pre_runcode_hook(self):
246 246 """ Executed before running the (prefiltered) code in IPython """
247 247 return None
248 248
249 249 def clipboard_get(self):
250 250 """ Get text from the clipboard.
251 251 """
252 252 from IPython.clipboard import (osx_clipboard_get, tkinter_clipboard_get,
253 253 win32_clipboard_get)
254 254 if sys.platform == 'win32':
255 255 chain = [win32_clipboard_get, tkinter_clipboard_get]
256 256 elif sys.platform == 'darwin':
257 257 chain = [osx_clipboard_get, tkinter_clipboard_get]
258 258 else:
259 259 chain = [tkinter_clipboard_get]
260 260 dispatcher = CommandChainDispatcher()
261 261 for func in chain:
262 262 dispatcher.add(func)
263 263 text = dispatcher()
264 264 return text
@@ -1,90 +1,90 b''
1 1 """Decorators for labeling test objects
2 2
3 3 Decorators that merely return a modified version of the original
4 4 function object are straightforward. Decorators that return a new
5 5 function object need to use
6 6 nose.tools.make_decorator(original_function)(decorator) in returning
7 7 the decorator, in order to preserve metadata such as function name,
8 8 setup and teardown functions and so on - see nose.tools for more
9 9 information.
10 10
11 11 """
12 12
13 13 def slow(t):
14 14 """Labels a test as 'slow'.
15 15
16 16 The exact definition of a slow test is obviously both subjective and
17 17 hardware-dependent, but in general any individual test that requires more
18 18 than a second or two should be labeled as slow (the whole suite consits of
19 19 thousands of tests, so even a second is significant)."""
20 20
21 21 t.slow = True
22 22 return t
23 23
24 24 def setastest(tf=True):
25 25 ''' Signals to nose that this function is or is not a test
26 26
27 27 Parameters
28 28 ----------
29 29 tf : bool
30 30 If True specifies this is a test, not a test otherwise
31 31
32 32 This decorator cannot use the nose namespace, because it can be
33 33 called from a non-test module. See also istest and nottest in
34 34 nose.tools
35 35
36 36 '''
37 37 def set_test(t):
38 38 t.__test__ = tf
39 39 return t
40 40 return set_test
41 41
42 42 def skipif(skip_condition=True, msg=None):
43 43 ''' Make function raise SkipTest exception if skip_condition is true
44 44
45 45 Parameters
46 46 ----------
47 47 skip_condition : bool or callable.
48 Flag to determine whether to skip test. If the condition is a
49 callable, it is used at runtime to dynamically make the decision. This
50 is useful for tests that may require costly imports, to delay the cost
51 until the test suite is actually executed.
48 Flag to determine whether to skip test. If the condition is a
49 callable, it is used at runtime to dynamically make the decision. This
50 is useful for tests that may require costly imports, to delay the cost
51 until the test suite is actually executed.
52 52 msg : string
53 53 Message to give on raising a SkipTest exception
54 54
55 55 Returns
56 56 -------
57 57 decorator : function
58 58 Decorator, which, when applied to a function, causes SkipTest
59 59 to be raised when the skip_condition was True, and the function
60 60 to be called normally otherwise.
61 61
62 62 Notes
63 63 -----
64 64 You will see from the code that we had to further decorate the
65 65 decorator with the nose.tools.make_decorator function in order to
66 66 transmit function name, and various other metadata.
67 67 '''
68 68 if msg is None:
69 69 msg = 'Test skipped due to test condition'
70 70 def skip_decorator(f):
71 71 # Local import to avoid a hard nose dependency and only incur the
72 72 # import time overhead at actual test-time.
73 73 import nose
74 74 def skipper(*args, **kwargs):
75 75 if skip_condition:
76 76 raise nose.SkipTest, msg
77 77 else:
78 78 return f(*args, **kwargs)
79 79 return nose.tools.make_decorator(f)(skipper)
80 80 return skip_decorator
81 81
82 82 def skipknownfailure(f):
83 83 ''' Decorator to raise SkipTest for test known to fail
84 84 '''
85 85 # Local import to avoid a hard nose dependency and only incur the
86 86 # import time overhead at actual test-time.
87 87 import nose
88 88 def skipper(*args, **kwargs):
89 89 raise nose.SkipTest, 'This test is known to fail'
90 90 return nose.tools.make_decorator(f)(skipper)
@@ -1,64 +1,64 b''
1 1 # encoding: utf-8
2 2 """This file contains utility classes for performing tests with Deferreds.
3 3 """
4 4 __docformat__ = "restructuredtext en"
5 5 #-------------------------------------------------------------------------------
6 6 # Copyright (C) 2005 Fernando Perez <fperez@colorado.edu>
7 7 # Brian E Granger <ellisonbg@gmail.com>
8 8 # Benjamin Ragan-Kelley <benjaminrk@gmail.com>
9 9 #
10 10 # Distributed under the terms of the BSD License. The full license is in
11 11 # the file COPYING, distributed as part of this software.
12 12 #-------------------------------------------------------------------------------
13 13
14 14 #-------------------------------------------------------------------------------
15 15 # Imports
16 16 #-------------------------------------------------------------------------------
17 17
18 18 from twisted.trial import unittest
19 19 from twisted.internet import defer
20 20
21 21 class DeferredTestCase(unittest.TestCase):
22 22
23 23 def assertDeferredEquals(self, deferred, expectedResult,
24 chainDeferred=None):
24 chainDeferred=None):
25 25 """Calls assertEquals on the result of the deferred and expectedResult.
26 26
27 27 chainDeferred can be used to pass in previous Deferred objects that
28 28 have tests being run on them. This chaining of Deferred's in tests
29 29 is needed to insure that all Deferred's are cleaned up at the end of
30 30 a test.
31 31 """
32 32
33 33 if chainDeferred is None:
34 34 chainDeferred = defer.succeed(None)
35
35
36 36 def gotResult(actualResult):
37 37 self.assertEquals(actualResult, expectedResult)
38 38
39 39 deferred.addCallback(gotResult)
40 40
41 41 return chainDeferred.addCallback(lambda _: deferred)
42 42
43 43 def assertDeferredRaises(self, deferred, expectedException,
44 chainDeferred=None):
44 chainDeferred=None):
45 45 """Calls assertRaises on the Failure of the deferred and expectedException.
46 46
47 47 chainDeferred can be used to pass in previous Deferred objects that
48 48 have tests being run on them. This chaining of Deferred's in tests
49 49 is needed to insure that all Deferred's are cleaned up at the end of
50 50 a test.
51 51 """
52 52
53 53 if chainDeferred is None:
54 54 chainDeferred = defer.succeed(None)
55 55
56 56 def gotFailure(f):
57 57 #f.printTraceback()
58 58 self.assertRaises(expectedException, f.raiseException)
59 59 #return f
60 60
61 61 deferred.addBoth(gotFailure)
62 62
63 63 return chainDeferred.addCallback(lambda _: deferred)
64 64
@@ -1,32 +1,54 b''
1 1 #!/usr/bin/env python
2 2 """Utility to look for hard tabs and \r characters in all sources.
3
4 Usage:
5
6 ./check_sources.py
7
8 It prints summaries and if chosen, line-by-line info of where \\t or \\r
9 characters can be found in our source tree.
3 10 """
4 11
5 from IPython.external.path import path
12 # Config
13 # If true, all lines that have tabs are printed, with line number
14 full_report_tabs = True
15 # If true, all lines that have tabs are printed, with line number
16 full_report_rets = False
6 17
7 fs = path('..').walkfiles('*.py')
18 # Code begins
19 from IPython.external.path import path
8 20
9 21 rets = []
22 tabs = []
10 23
11 for f in fs:
24 for f in path('..').walkfiles('*.py'):
12 25 errs = ''
13 26 cont = f.bytes()
14 27 if '\t' in cont:
15 28 errs+='t'
29 tabs.append(f)
16 30
17 31 if '\r' in cont:
18 32 errs+='r'
19 33 rets.append(f)
20 34
21 35 if errs:
22 36 print "%3s" % errs, f
23 if 't' in errs:
24 for ln,line in enumerate(f.lines()):
25 if '\t' in line:
26 print 'TAB:',ln,':',line,
27 if 'r' in errs:
28 for ln,line in enumerate(open(f.abspath(),'rb')):
29 if '\r' in line:
30 print 'RET:',ln,':',line,
31
32 rr = rets[-1]
37
38 if 't' in errs and full_report_tabs:
39 for ln,line in enumerate(f.lines()):
40 if '\t' in line:
41 print 'TAB:',ln,':',line,
42
43 if 'r' in errs and full_report_rets:
44 for ln,line in enumerate(open(f.abspath(),'rb')):
45 if '\r' in line:
46 print 'RET:',ln,':',line,
47
48 # Summary at the end, to call cleanup tools if necessary
49 if tabs:
50 print 'Hard tabs found. These can be cleaned with untabify:'
51 for f in tabs: print f,
52 if rets:
53 print 'Carriage returns (\\r) found in:'
54 for f in rets: print f,
General Comments 0
You need to be logged in to leave comments. Login now