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