##// END OF EJS Templates
Minimal changes to import IPython from IronPython
Doug Blank -
Show More
@@ -0,0 +1,61 b''
1 """
2 cli-specific implementation of process utilities.
3
4 cli - Common Language Infrastructure for IronPython. Code
5 can run on any operating system. Check os.name for os-
6 specific settings.
7
8 This file is only meant to be imported by process.py, not by end-users.
9 """
10
11 # Import cli libraries:
12 import clr
13 import System
14
15 # Import Python libraries:
16 import os
17
18 # Import IPython libraries:
19 from IPython.utils import py3compat
20 from ._process_common import arg_split
21
22 def _find_cmd(cmd):
23 """Find the full path to a command using which."""
24 os_path_sep = ":" if os.name == "posix" else ";"
25 paths = System.Environment.GetEnvironmentVariable("PATH").Split(os_path_sep)
26 for path in paths:
27 filename = os.path.join(path, cmd)
28 if System.IO.File.Exists(filename):
29 return py3compat.bytes_to_str(filename)
30 raise OSError("command %r not found" % cmd)
31
32 def system(cmd):
33 """
34 system(cmd) should work in a cli environment on Mac OSX, Linux,
35 and Windows
36 """
37 psi = System.Diagnostics.ProcessStartInfo(cmd)
38 psi.RedirectStandardOutput = True
39 psi.RedirectStandardError = True
40 psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal
41 psi.UseShellExecute = False
42 # Start up process:
43 reg = System.Diagnostics.Process.Start(psi)
44
45 def getoutput(cmd):
46 """
47 getoutput(cmd) should work in a cli environment on Mac OSX, Linux,
48 and Windows
49 """
50 psi = System.Diagnostics.ProcessStartInfo(cmd)
51 psi.RedirectStandardOutput = True
52 psi.RedirectStandardError = True
53 psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal
54 psi.UseShellExecute = False
55 # Start up process:
56 reg = System.Diagnostics.Process.Start(psi)
57 myOutput = reg.StandardOutput
58 output = myOutput.ReadToEnd()
59 myError = reg.StandardError
60 error = myError.ReadToEnd()
61 return output
@@ -1,144 +1,147 b''
1 1 """Compiler tools with improved interactive support.
2 2
3 3 Provides compilation machinery similar to codeop, but with caching support so
4 4 we can provide interactive tracebacks.
5 5
6 6 Authors
7 7 -------
8 8 * Robert Kern
9 9 * Fernando Perez
10 10 * Thomas Kluyver
11 11 """
12 12
13 13 # Note: though it might be more natural to name this module 'compiler', that
14 14 # name is in the stdlib and name collisions with the stdlib tend to produce
15 15 # weird problems (often with third-party tools).
16 16
17 17 #-----------------------------------------------------------------------------
18 18 # Copyright (C) 2010-2011 The IPython Development Team.
19 19 #
20 20 # Distributed under the terms of the BSD License.
21 21 #
22 22 # The full license is in the file COPYING.txt, distributed with this software.
23 23 #-----------------------------------------------------------------------------
24 24
25 25 #-----------------------------------------------------------------------------
26 26 # Imports
27 27 #-----------------------------------------------------------------------------
28 28 from __future__ import print_function
29 29
30 30 # Stdlib imports
31 31 import __future__
32 32 from ast import PyCF_ONLY_AST
33 33 import codeop
34 34 import functools
35 35 import hashlib
36 36 import linecache
37 37 import operator
38 38 import time
39 39
40 40 #-----------------------------------------------------------------------------
41 41 # Constants
42 42 #-----------------------------------------------------------------------------
43 43
44 44 # Roughtly equal to PyCF_MASK | PyCF_MASK_OBSOLETE as defined in pythonrun.h,
45 45 # this is used as a bitmask to extract future-related code flags.
46 46 PyCF_MASK = functools.reduce(operator.or_,
47 47 (getattr(__future__, fname).compiler_flag
48 for fname in __future__.all_feature_names))
48 for fname in __future__.all_feature_names
49 if (hasattr(__future__, fname) and
50 hasattr(getattr(__future__, fname), "compiler_flag"))),
51 0)
49 52
50 53 #-----------------------------------------------------------------------------
51 54 # Local utilities
52 55 #-----------------------------------------------------------------------------
53 56
54 57 def code_name(code, number=0):
55 58 """ Compute a (probably) unique name for code for caching.
56 59
57 60 This now expects code to be unicode.
58 61 """
59 62 hash_digest = hashlib.md5(code.encode("utf-8")).hexdigest()
60 63 # Include the number and 12 characters of the hash in the name. It's
61 64 # pretty much impossible that in a single session we'll have collisions
62 65 # even with truncated hashes, and the full one makes tracebacks too long
63 66 return '<ipython-input-{0}-{1}>'.format(number, hash_digest[:12])
64 67
65 68 #-----------------------------------------------------------------------------
66 69 # Classes and functions
67 70 #-----------------------------------------------------------------------------
68 71
69 72 class CachingCompiler(codeop.Compile):
70 73 """A compiler that caches code compiled from interactive statements.
71 74 """
72 75
73 76 def __init__(self):
74 77 codeop.Compile.__init__(self)
75 78
76 79 # This is ugly, but it must be done this way to allow multiple
77 80 # simultaneous ipython instances to coexist. Since Python itself
78 81 # directly accesses the data structures in the linecache module, and
79 82 # the cache therein is global, we must work with that data structure.
80 83 # We must hold a reference to the original checkcache routine and call
81 84 # that in our own check_cache() below, but the special IPython cache
82 85 # must also be shared by all IPython instances. If we were to hold
83 86 # separate caches (one in each CachingCompiler instance), any call made
84 87 # by Python itself to linecache.checkcache() would obliterate the
85 88 # cached data from the other IPython instances.
86 89 if not hasattr(linecache, '_ipython_cache'):
87 90 linecache._ipython_cache = {}
88 91 if not hasattr(linecache, '_checkcache_ori'):
89 92 linecache._checkcache_ori = linecache.checkcache
90 93 # Now, we must monkeypatch the linecache directly so that parts of the
91 94 # stdlib that call it outside our control go through our codepath
92 95 # (otherwise we'd lose our tracebacks).
93 96 linecache.checkcache = check_linecache_ipython
94 97
95 98 def ast_parse(self, source, filename='<unknown>', symbol='exec'):
96 99 """Parse code to an AST with the current compiler flags active.
97 100
98 101 Arguments are exactly the same as ast.parse (in the standard library),
99 102 and are passed to the built-in compile function."""
100 103 return compile(source, filename, symbol, self.flags | PyCF_ONLY_AST, 1)
101 104
102 105 def reset_compiler_flags(self):
103 106 """Reset compiler flags to default state."""
104 107 # This value is copied from codeop.Compile.__init__, so if that ever
105 108 # changes, it will need to be updated.
106 109 self.flags = codeop.PyCF_DONT_IMPLY_DEDENT
107 110
108 111 @property
109 112 def compiler_flags(self):
110 113 """Flags currently active in the compilation process.
111 114 """
112 115 return self.flags
113 116
114 117 def cache(self, code, number=0):
115 118 """Make a name for a block of code, and cache the code.
116 119
117 120 Parameters
118 121 ----------
119 122 code : str
120 123 The Python source code to cache.
121 124 number : int
122 125 A number which forms part of the code's name. Used for the execution
123 126 counter.
124 127
125 128 Returns
126 129 -------
127 130 The name of the cached code (as a string). Pass this as the filename
128 131 argument to compilation, so that tracebacks are correctly hooked up.
129 132 """
130 133 name = code_name(code, number)
131 134 entry = (len(code), time.time(),
132 135 [line+'\n' for line in code.splitlines()], name)
133 136 linecache.cache[name] = entry
134 137 linecache._ipython_cache[name] = entry
135 138 return name
136 139
137 140 def check_linecache_ipython(*args):
138 141 """Call linecache.checkcache() safely protecting our cached values.
139 142 """
140 143 # First call the orignal checkcache as intended
141 144 linecache._checkcache_ori(*args)
142 145 # Then, update back the cache with our data, so that tracebacks related
143 146 # to our compiled codes can be produced.
144 147 linecache.cache.update(linecache._ipython_cache)
@@ -1,997 +1,1000 b''
1 1 """Word completion for IPython.
2 2
3 3 This module is a fork of the rlcompleter module in the Python standard
4 4 library. The original enhancements made to rlcompleter have been sent
5 5 upstream and were accepted as of Python 2.3, but we need a lot more
6 6 functionality specific to IPython, so this module will continue to live as an
7 7 IPython-specific utility.
8 8
9 9 Original rlcompleter documentation:
10 10
11 11 This requires the latest extension to the readline module (the
12 12 completes keywords, built-ins and globals in __main__; when completing
13 13 NAME.NAME..., it evaluates (!) the expression up to the last dot and
14 14 completes its attributes.
15 15
16 16 It's very cool to do "import string" type "string.", hit the
17 17 completion key (twice), and see the list of names defined by the
18 18 string module!
19 19
20 20 Tip: to use the tab key as the completion key, call
21 21
22 22 readline.parse_and_bind("tab: complete")
23 23
24 24 Notes:
25 25
26 26 - Exceptions raised by the completer function are *ignored* (and
27 27 generally cause the completion to fail). This is a feature -- since
28 28 readline sets the tty device in raw (or cbreak) mode, printing a
29 29 traceback wouldn't work well without some complicated hoopla to save,
30 30 reset and restore the tty state.
31 31
32 32 - The evaluation of the NAME.NAME... form may cause arbitrary
33 33 application defined code to be executed if an object with a
34 34 ``__getattr__`` hook is found. Since it is the responsibility of the
35 35 application (or the user) to enable this feature, I consider this an
36 36 acceptable risk. More complicated expressions (e.g. function calls or
37 37 indexing operations) are *not* evaluated.
38 38
39 39 - GNU readline is also used by the built-in functions input() and
40 40 raw_input(), and thus these also benefit/suffer from the completer
41 41 features. Clearly an interactive application can benefit by
42 42 specifying its own completer function and using raw_input() for all
43 43 its input.
44 44
45 45 - When the original stdin is not a tty device, GNU readline is never
46 46 used, and this module (and the readline module) are silently inactive.
47 47 """
48 48
49 49 #*****************************************************************************
50 50 #
51 51 # Since this file is essentially a minimally modified copy of the rlcompleter
52 52 # module which is part of the standard Python distribution, I assume that the
53 53 # proper procedure is to maintain its copyright as belonging to the Python
54 54 # Software Foundation (in addition to my own, for all new code).
55 55 #
56 56 # Copyright (C) 2008 IPython Development Team
57 57 # Copyright (C) 2001 Fernando Perez. <fperez@colorado.edu>
58 58 # Copyright (C) 2001 Python Software Foundation, www.python.org
59 59 #
60 60 # Distributed under the terms of the BSD License. The full license is in
61 61 # the file COPYING, distributed as part of this software.
62 62 #
63 63 #*****************************************************************************
64 64
65 65 #-----------------------------------------------------------------------------
66 66 # Imports
67 67 #-----------------------------------------------------------------------------
68 68
69 import __main__
69 try:
70 import __main__
71 except ImportError:
72 pass
70 73 import glob
71 74 import inspect
72 75 import itertools
73 76 import keyword
74 77 import os
75 78 import re
76 79 import sys
77 80
78 81 from IPython.config.configurable import Configurable
79 82 from IPython.core.error import TryNext
80 83 from IPython.core.inputsplitter import ESC_MAGIC
81 84 from IPython.utils import generics
82 85 from IPython.utils import io
83 86 from IPython.utils.dir2 import dir2
84 87 from IPython.utils.process import arg_split
85 88 from IPython.utils.py3compat import builtin_mod, string_types
86 89 from IPython.utils.traitlets import CBool, Enum
87 90
88 91 #-----------------------------------------------------------------------------
89 92 # Globals
90 93 #-----------------------------------------------------------------------------
91 94
92 95 # Public API
93 96 __all__ = ['Completer','IPCompleter']
94 97
95 98 if sys.platform == 'win32':
96 99 PROTECTABLES = ' '
97 100 else:
98 101 PROTECTABLES = ' ()[]{}?=\\|;:\'#*"^&'
99 102
100 103 #-----------------------------------------------------------------------------
101 104 # Main functions and classes
102 105 #-----------------------------------------------------------------------------
103 106
104 107 def has_open_quotes(s):
105 108 """Return whether a string has open quotes.
106 109
107 110 This simply counts whether the number of quote characters of either type in
108 111 the string is odd.
109 112
110 113 Returns
111 114 -------
112 115 If there is an open quote, the quote character is returned. Else, return
113 116 False.
114 117 """
115 118 # We check " first, then ', so complex cases with nested quotes will get
116 119 # the " to take precedence.
117 120 if s.count('"') % 2:
118 121 return '"'
119 122 elif s.count("'") % 2:
120 123 return "'"
121 124 else:
122 125 return False
123 126
124 127
125 128 def protect_filename(s):
126 129 """Escape a string to protect certain characters."""
127 130
128 131 return "".join([(ch in PROTECTABLES and '\\' + ch or ch)
129 132 for ch in s])
130 133
131 134 def expand_user(path):
132 135 """Expand '~'-style usernames in strings.
133 136
134 137 This is similar to :func:`os.path.expanduser`, but it computes and returns
135 138 extra information that will be useful if the input was being used in
136 139 computing completions, and you wish to return the completions with the
137 140 original '~' instead of its expanded value.
138 141
139 142 Parameters
140 143 ----------
141 144 path : str
142 145 String to be expanded. If no ~ is present, the output is the same as the
143 146 input.
144 147
145 148 Returns
146 149 -------
147 150 newpath : str
148 151 Result of ~ expansion in the input path.
149 152 tilde_expand : bool
150 153 Whether any expansion was performed or not.
151 154 tilde_val : str
152 155 The value that ~ was replaced with.
153 156 """
154 157 # Default values
155 158 tilde_expand = False
156 159 tilde_val = ''
157 160 newpath = path
158 161
159 162 if path.startswith('~'):
160 163 tilde_expand = True
161 164 rest = len(path)-1
162 165 newpath = os.path.expanduser(path)
163 166 if rest:
164 167 tilde_val = newpath[:-rest]
165 168 else:
166 169 tilde_val = newpath
167 170
168 171 return newpath, tilde_expand, tilde_val
169 172
170 173
171 174 def compress_user(path, tilde_expand, tilde_val):
172 175 """Does the opposite of expand_user, with its outputs.
173 176 """
174 177 if tilde_expand:
175 178 return path.replace(tilde_val, '~')
176 179 else:
177 180 return path
178 181
179 182
180 183
181 184 def penalize_magics_key(word):
182 185 """key for sorting that penalizes magic commands in the ordering
183 186
184 187 Normal words are left alone.
185 188
186 189 Magic commands have the initial % moved to the end, e.g.
187 190 %matplotlib is transformed as follows:
188 191
189 192 %matplotlib -> matplotlib%
190 193
191 194 [The choice of the final % is arbitrary.]
192 195
193 196 Since "matplotlib" < "matplotlib%" as strings,
194 197 "timeit" will appear before the magic "%timeit" in the ordering
195 198
196 199 For consistency, move "%%" to the end, so cell magics appear *after*
197 200 line magics with the same name.
198 201
199 202 A check is performed that there are no other "%" in the string;
200 203 if there are, then the string is not a magic command and is left unchanged.
201 204
202 205 """
203 206
204 207 # Move any % signs from start to end of the key
205 208 # provided there are no others elsewhere in the string
206 209
207 210 if word[:2] == "%%":
208 211 if not "%" in word[2:]:
209 212 return word[2:] + "%%"
210 213
211 214 if word[:1] == "%":
212 215 if not "%" in word[1:]:
213 216 return word[1:] + "%"
214 217
215 218 return word
216 219
217 220
218 221
219 222 class Bunch(object): pass
220 223
221 224
222 225 DELIMS = ' \t\n`!@#$^&*()=+[{]}\\|;:\'",<>?'
223 226 GREEDY_DELIMS = ' =\r\n'
224 227
225 228
226 229 class CompletionSplitter(object):
227 230 """An object to split an input line in a manner similar to readline.
228 231
229 232 By having our own implementation, we can expose readline-like completion in
230 233 a uniform manner to all frontends. This object only needs to be given the
231 234 line of text to be split and the cursor position on said line, and it
232 235 returns the 'word' to be completed on at the cursor after splitting the
233 236 entire line.
234 237
235 238 What characters are used as splitting delimiters can be controlled by
236 239 setting the `delims` attribute (this is a property that internally
237 240 automatically builds the necessary regular expression)"""
238 241
239 242 # Private interface
240 243
241 244 # A string of delimiter characters. The default value makes sense for
242 245 # IPython's most typical usage patterns.
243 246 _delims = DELIMS
244 247
245 248 # The expression (a normal string) to be compiled into a regular expression
246 249 # for actual splitting. We store it as an attribute mostly for ease of
247 250 # debugging, since this type of code can be so tricky to debug.
248 251 _delim_expr = None
249 252
250 253 # The regular expression that does the actual splitting
251 254 _delim_re = None
252 255
253 256 def __init__(self, delims=None):
254 257 delims = CompletionSplitter._delims if delims is None else delims
255 258 self.delims = delims
256 259
257 260 @property
258 261 def delims(self):
259 262 """Return the string of delimiter characters."""
260 263 return self._delims
261 264
262 265 @delims.setter
263 266 def delims(self, delims):
264 267 """Set the delimiters for line splitting."""
265 268 expr = '[' + ''.join('\\'+ c for c in delims) + ']'
266 269 self._delim_re = re.compile(expr)
267 270 self._delims = delims
268 271 self._delim_expr = expr
269 272
270 273 def split_line(self, line, cursor_pos=None):
271 274 """Split a line of text with a cursor at the given position.
272 275 """
273 276 l = line if cursor_pos is None else line[:cursor_pos]
274 277 return self._delim_re.split(l)[-1]
275 278
276 279
277 280 class Completer(Configurable):
278 281
279 282 greedy = CBool(False, config=True,
280 283 help="""Activate greedy completion
281 284
282 285 This will enable completion on elements of lists, results of function calls, etc.,
283 286 but can be unsafe because the code is actually evaluated on TAB.
284 287 """
285 288 )
286 289
287 290
288 291 def __init__(self, namespace=None, global_namespace=None, **kwargs):
289 292 """Create a new completer for the command line.
290 293
291 294 Completer(namespace=ns,global_namespace=ns2) -> completer instance.
292 295
293 296 If unspecified, the default namespace where completions are performed
294 297 is __main__ (technically, __main__.__dict__). Namespaces should be
295 298 given as dictionaries.
296 299
297 300 An optional second namespace can be given. This allows the completer
298 301 to handle cases where both the local and global scopes need to be
299 302 distinguished.
300 303
301 304 Completer instances should be used as the completion mechanism of
302 305 readline via the set_completer() call:
303 306
304 307 readline.set_completer(Completer(my_namespace).complete)
305 308 """
306 309
307 310 # Don't bind to namespace quite yet, but flag whether the user wants a
308 311 # specific namespace or to use __main__.__dict__. This will allow us
309 312 # to bind to __main__.__dict__ at completion time, not now.
310 313 if namespace is None:
311 314 self.use_main_ns = 1
312 315 else:
313 316 self.use_main_ns = 0
314 317 self.namespace = namespace
315 318
316 319 # The global namespace, if given, can be bound directly
317 320 if global_namespace is None:
318 321 self.global_namespace = {}
319 322 else:
320 323 self.global_namespace = global_namespace
321 324
322 325 super(Completer, self).__init__(**kwargs)
323 326
324 327 def complete(self, text, state):
325 328 """Return the next possible completion for 'text'.
326 329
327 330 This is called successively with state == 0, 1, 2, ... until it
328 331 returns None. The completion should begin with 'text'.
329 332
330 333 """
331 334 if self.use_main_ns:
332 335 self.namespace = __main__.__dict__
333 336
334 337 if state == 0:
335 338 if "." in text:
336 339 self.matches = self.attr_matches(text)
337 340 else:
338 341 self.matches = self.global_matches(text)
339 342 try:
340 343 return self.matches[state]
341 344 except IndexError:
342 345 return None
343 346
344 347 def global_matches(self, text):
345 348 """Compute matches when text is a simple name.
346 349
347 350 Return a list of all keywords, built-in functions and names currently
348 351 defined in self.namespace or self.global_namespace that match.
349 352
350 353 """
351 354 #print 'Completer->global_matches, txt=%r' % text # dbg
352 355 matches = []
353 356 match_append = matches.append
354 357 n = len(text)
355 358 for lst in [keyword.kwlist,
356 359 builtin_mod.__dict__.keys(),
357 360 self.namespace.keys(),
358 361 self.global_namespace.keys()]:
359 362 for word in lst:
360 363 if word[:n] == text and word != "__builtins__":
361 364 match_append(word)
362 365 return matches
363 366
364 367 def attr_matches(self, text):
365 368 """Compute matches when text contains a dot.
366 369
367 370 Assuming the text is of the form NAME.NAME....[NAME], and is
368 371 evaluatable in self.namespace or self.global_namespace, it will be
369 372 evaluated and its attributes (as revealed by dir()) are used as
370 373 possible completions. (For class instances, class members are are
371 374 also considered.)
372 375
373 376 WARNING: this can still invoke arbitrary C code, if an object
374 377 with a __getattr__ hook is evaluated.
375 378
376 379 """
377 380
378 381 #io.rprint('Completer->attr_matches, txt=%r' % text) # dbg
379 382 # Another option, seems to work great. Catches things like ''.<tab>
380 383 m = re.match(r"(\S+(\.\w+)*)\.(\w*)$", text)
381 384
382 385 if m:
383 386 expr, attr = m.group(1, 3)
384 387 elif self.greedy:
385 388 m2 = re.match(r"(.+)\.(\w*)$", self.line_buffer)
386 389 if not m2:
387 390 return []
388 391 expr, attr = m2.group(1,2)
389 392 else:
390 393 return []
391 394
392 395 try:
393 396 obj = eval(expr, self.namespace)
394 397 except:
395 398 try:
396 399 obj = eval(expr, self.global_namespace)
397 400 except:
398 401 return []
399 402
400 403 if self.limit_to__all__ and hasattr(obj, '__all__'):
401 404 words = get__all__entries(obj)
402 405 else:
403 406 words = dir2(obj)
404 407
405 408 try:
406 409 words = generics.complete_object(obj, words)
407 410 except TryNext:
408 411 pass
409 412 except Exception:
410 413 # Silence errors from completion function
411 414 #raise # dbg
412 415 pass
413 416 # Build match list to return
414 417 n = len(attr)
415 418 res = ["%s.%s" % (expr, w) for w in words if w[:n] == attr ]
416 419 return res
417 420
418 421
419 422 def get__all__entries(obj):
420 423 """returns the strings in the __all__ attribute"""
421 424 try:
422 425 words = getattr(obj, '__all__')
423 426 except:
424 427 return []
425 428
426 429 return [w for w in words if isinstance(w, string_types)]
427 430
428 431
429 432 class IPCompleter(Completer):
430 433 """Extension of the completer class with IPython-specific features"""
431 434
432 435 def _greedy_changed(self, name, old, new):
433 436 """update the splitter and readline delims when greedy is changed"""
434 437 if new:
435 438 self.splitter.delims = GREEDY_DELIMS
436 439 else:
437 440 self.splitter.delims = DELIMS
438 441
439 442 if self.readline:
440 443 self.readline.set_completer_delims(self.splitter.delims)
441 444
442 445 merge_completions = CBool(True, config=True,
443 446 help="""Whether to merge completion results into a single list
444 447
445 448 If False, only the completion results from the first non-empty
446 449 completer will be returned.
447 450 """
448 451 )
449 452 omit__names = Enum((0,1,2), default_value=2, config=True,
450 453 help="""Instruct the completer to omit private method names
451 454
452 455 Specifically, when completing on ``object.<tab>``.
453 456
454 457 When 2 [default]: all names that start with '_' will be excluded.
455 458
456 459 When 1: all 'magic' names (``__foo__``) will be excluded.
457 460
458 461 When 0: nothing will be excluded.
459 462 """
460 463 )
461 464 limit_to__all__ = CBool(default_value=False, config=True,
462 465 help="""Instruct the completer to use __all__ for the completion
463 466
464 467 Specifically, when completing on ``object.<tab>``.
465 468
466 469 When True: only those names in obj.__all__ will be included.
467 470
468 471 When False [default]: the __all__ attribute is ignored
469 472 """
470 473 )
471 474
472 475 def __init__(self, shell=None, namespace=None, global_namespace=None,
473 476 use_readline=True, config=None, **kwargs):
474 477 """IPCompleter() -> completer
475 478
476 479 Return a completer object suitable for use by the readline library
477 480 via readline.set_completer().
478 481
479 482 Inputs:
480 483
481 484 - shell: a pointer to the ipython shell itself. This is needed
482 485 because this completer knows about magic functions, and those can
483 486 only be accessed via the ipython instance.
484 487
485 488 - namespace: an optional dict where completions are performed.
486 489
487 490 - global_namespace: secondary optional dict for completions, to
488 491 handle cases (such as IPython embedded inside functions) where
489 492 both Python scopes are visible.
490 493
491 494 use_readline : bool, optional
492 495 If true, use the readline library. This completer can still function
493 496 without readline, though in that case callers must provide some extra
494 497 information on each call about the current line."""
495 498
496 499 self.magic_escape = ESC_MAGIC
497 500 self.splitter = CompletionSplitter()
498 501
499 502 # Readline configuration, only used by the rlcompleter method.
500 503 if use_readline:
501 504 # We store the right version of readline so that later code
502 505 import IPython.utils.rlineimpl as readline
503 506 self.readline = readline
504 507 else:
505 508 self.readline = None
506 509
507 510 # _greedy_changed() depends on splitter and readline being defined:
508 511 Completer.__init__(self, namespace=namespace, global_namespace=global_namespace,
509 512 config=config, **kwargs)
510 513
511 514 # List where completion matches will be stored
512 515 self.matches = []
513 516 self.shell = shell
514 517 # Regexp to split filenames with spaces in them
515 518 self.space_name_re = re.compile(r'([^\\] )')
516 519 # Hold a local ref. to glob.glob for speed
517 520 self.glob = glob.glob
518 521
519 522 # Determine if we are running on 'dumb' terminals, like (X)Emacs
520 523 # buffers, to avoid completion problems.
521 524 term = os.environ.get('TERM','xterm')
522 525 self.dumb_terminal = term in ['dumb','emacs']
523 526
524 527 # Special handling of backslashes needed in win32 platforms
525 528 if sys.platform == "win32":
526 529 self.clean_glob = self._clean_glob_win32
527 530 else:
528 531 self.clean_glob = self._clean_glob
529 532
530 533 #regexp to parse docstring for function signature
531 534 self.docstring_sig_re = re.compile(r'^[\w|\s.]+\(([^)]*)\).*')
532 535 self.docstring_kwd_re = re.compile(r'[\s|\[]*(\w+)(?:\s*=\s*.*)')
533 536 #use this if positional argument name is also needed
534 537 #= re.compile(r'[\s|\[]*(\w+)(?:\s*=?\s*.*)')
535 538
536 539 # All active matcher routines for completion
537 540 self.matchers = [self.python_matches,
538 541 self.file_matches,
539 542 self.magic_matches,
540 543 self.python_func_kw_matches,
541 544 ]
542 545
543 546 def all_completions(self, text):
544 547 """
545 548 Wrapper around the complete method for the benefit of emacs
546 549 and pydb.
547 550 """
548 551 return self.complete(text)[1]
549 552
550 553 def _clean_glob(self,text):
551 554 return self.glob("%s*" % text)
552 555
553 556 def _clean_glob_win32(self,text):
554 557 return [f.replace("\\","/")
555 558 for f in self.glob("%s*" % text)]
556 559
557 560 def file_matches(self, text):
558 561 """Match filenames, expanding ~USER type strings.
559 562
560 563 Most of the seemingly convoluted logic in this completer is an
561 564 attempt to handle filenames with spaces in them. And yet it's not
562 565 quite perfect, because Python's readline doesn't expose all of the
563 566 GNU readline details needed for this to be done correctly.
564 567
565 568 For a filename with a space in it, the printed completions will be
566 569 only the parts after what's already been typed (instead of the
567 570 full completions, as is normally done). I don't think with the
568 571 current (as of Python 2.3) Python readline it's possible to do
569 572 better."""
570 573
571 574 #io.rprint('Completer->file_matches: <%r>' % text) # dbg
572 575
573 576 # chars that require escaping with backslash - i.e. chars
574 577 # that readline treats incorrectly as delimiters, but we
575 578 # don't want to treat as delimiters in filename matching
576 579 # when escaped with backslash
577 580 if text.startswith('!'):
578 581 text = text[1:]
579 582 text_prefix = '!'
580 583 else:
581 584 text_prefix = ''
582 585
583 586 text_until_cursor = self.text_until_cursor
584 587 # track strings with open quotes
585 588 open_quotes = has_open_quotes(text_until_cursor)
586 589
587 590 if '(' in text_until_cursor or '[' in text_until_cursor:
588 591 lsplit = text
589 592 else:
590 593 try:
591 594 # arg_split ~ shlex.split, but with unicode bugs fixed by us
592 595 lsplit = arg_split(text_until_cursor)[-1]
593 596 except ValueError:
594 597 # typically an unmatched ", or backslash without escaped char.
595 598 if open_quotes:
596 599 lsplit = text_until_cursor.split(open_quotes)[-1]
597 600 else:
598 601 return []
599 602 except IndexError:
600 603 # tab pressed on empty line
601 604 lsplit = ""
602 605
603 606 if not open_quotes and lsplit != protect_filename(lsplit):
604 607 # if protectables are found, do matching on the whole escaped name
605 608 has_protectables = True
606 609 text0,text = text,lsplit
607 610 else:
608 611 has_protectables = False
609 612 text = os.path.expanduser(text)
610 613
611 614 if text == "":
612 615 return [text_prefix + protect_filename(f) for f in self.glob("*")]
613 616
614 617 # Compute the matches from the filesystem
615 618 m0 = self.clean_glob(text.replace('\\',''))
616 619
617 620 if has_protectables:
618 621 # If we had protectables, we need to revert our changes to the
619 622 # beginning of filename so that we don't double-write the part
620 623 # of the filename we have so far
621 624 len_lsplit = len(lsplit)
622 625 matches = [text_prefix + text0 +
623 626 protect_filename(f[len_lsplit:]) for f in m0]
624 627 else:
625 628 if open_quotes:
626 629 # if we have a string with an open quote, we don't need to
627 630 # protect the names at all (and we _shouldn't_, as it
628 631 # would cause bugs when the filesystem call is made).
629 632 matches = m0
630 633 else:
631 634 matches = [text_prefix +
632 635 protect_filename(f) for f in m0]
633 636
634 637 #io.rprint('mm', matches) # dbg
635 638
636 639 # Mark directories in input list by appending '/' to their names.
637 640 matches = [x+'/' if os.path.isdir(x) else x for x in matches]
638 641 return matches
639 642
640 643 def magic_matches(self, text):
641 644 """Match magics"""
642 645 #print 'Completer->magic_matches:',text,'lb',self.text_until_cursor # dbg
643 646 # Get all shell magics now rather than statically, so magics loaded at
644 647 # runtime show up too.
645 648 lsm = self.shell.magics_manager.lsmagic()
646 649 line_magics = lsm['line']
647 650 cell_magics = lsm['cell']
648 651 pre = self.magic_escape
649 652 pre2 = pre+pre
650 653
651 654 # Completion logic:
652 655 # - user gives %%: only do cell magics
653 656 # - user gives %: do both line and cell magics
654 657 # - no prefix: do both
655 658 # In other words, line magics are skipped if the user gives %% explicitly
656 659 bare_text = text.lstrip(pre)
657 660 comp = [ pre2+m for m in cell_magics if m.startswith(bare_text)]
658 661 if not text.startswith(pre2):
659 662 comp += [ pre+m for m in line_magics if m.startswith(bare_text)]
660 663 return comp
661 664
662 665 def python_matches(self,text):
663 666 """Match attributes or global python names"""
664 667
665 668 #io.rprint('Completer->python_matches, txt=%r' % text) # dbg
666 669 if "." in text:
667 670 try:
668 671 matches = self.attr_matches(text)
669 672 if text.endswith('.') and self.omit__names:
670 673 if self.omit__names == 1:
671 674 # true if txt is _not_ a __ name, false otherwise:
672 675 no__name = (lambda txt:
673 676 re.match(r'.*\.__.*?__',txt) is None)
674 677 else:
675 678 # true if txt is _not_ a _ name, false otherwise:
676 679 no__name = (lambda txt:
677 680 re.match(r'.*\._.*?',txt) is None)
678 681 matches = filter(no__name, matches)
679 682 except NameError:
680 683 # catches <undefined attributes>.<tab>
681 684 matches = []
682 685 else:
683 686 matches = self.global_matches(text)
684 687
685 688 return matches
686 689
687 690 def _default_arguments_from_docstring(self, doc):
688 691 """Parse the first line of docstring for call signature.
689 692
690 693 Docstring should be of the form 'min(iterable[, key=func])\n'.
691 694 It can also parse cython docstring of the form
692 695 'Minuit.migrad(self, int ncall=10000, resume=True, int nsplit=1)'.
693 696 """
694 697 if doc is None:
695 698 return []
696 699
697 700 #care only the firstline
698 701 line = doc.lstrip().splitlines()[0]
699 702
700 703 #p = re.compile(r'^[\w|\s.]+\(([^)]*)\).*')
701 704 #'min(iterable[, key=func])\n' -> 'iterable[, key=func]'
702 705 sig = self.docstring_sig_re.search(line)
703 706 if sig is None:
704 707 return []
705 708 # iterable[, key=func]' -> ['iterable[' ,' key=func]']
706 709 sig = sig.groups()[0].split(',')
707 710 ret = []
708 711 for s in sig:
709 712 #re.compile(r'[\s|\[]*(\w+)(?:\s*=\s*.*)')
710 713 ret += self.docstring_kwd_re.findall(s)
711 714 return ret
712 715
713 716 def _default_arguments(self, obj):
714 717 """Return the list of default arguments of obj if it is callable,
715 718 or empty list otherwise."""
716 719 call_obj = obj
717 720 ret = []
718 721 if inspect.isbuiltin(obj):
719 722 pass
720 723 elif not (inspect.isfunction(obj) or inspect.ismethod(obj)):
721 724 if inspect.isclass(obj):
722 725 #for cython embededsignature=True the constructor docstring
723 726 #belongs to the object itself not __init__
724 727 ret += self._default_arguments_from_docstring(
725 728 getattr(obj, '__doc__', ''))
726 729 # for classes, check for __init__,__new__
727 730 call_obj = (getattr(obj, '__init__', None) or
728 731 getattr(obj, '__new__', None))
729 732 # for all others, check if they are __call__able
730 733 elif hasattr(obj, '__call__'):
731 734 call_obj = obj.__call__
732 735
733 736 ret += self._default_arguments_from_docstring(
734 737 getattr(call_obj, '__doc__', ''))
735 738
736 739 try:
737 740 args,_,_1,defaults = inspect.getargspec(call_obj)
738 741 if defaults:
739 742 ret+=args[-len(defaults):]
740 743 except TypeError:
741 744 pass
742 745
743 746 return list(set(ret))
744 747
745 748 def python_func_kw_matches(self,text):
746 749 """Match named parameters (kwargs) of the last open function"""
747 750
748 751 if "." in text: # a parameter cannot be dotted
749 752 return []
750 753 try: regexp = self.__funcParamsRegex
751 754 except AttributeError:
752 755 regexp = self.__funcParamsRegex = re.compile(r'''
753 756 '.*?(?<!\\)' | # single quoted strings or
754 757 ".*?(?<!\\)" | # double quoted strings or
755 758 \w+ | # identifier
756 759 \S # other characters
757 760 ''', re.VERBOSE | re.DOTALL)
758 761 # 1. find the nearest identifier that comes before an unclosed
759 762 # parenthesis before the cursor
760 763 # e.g. for "foo (1+bar(x), pa<cursor>,a=1)", the candidate is "foo"
761 764 tokens = regexp.findall(self.text_until_cursor)
762 765 tokens.reverse()
763 766 iterTokens = iter(tokens); openPar = 0
764 767
765 768 for token in iterTokens:
766 769 if token == ')':
767 770 openPar -= 1
768 771 elif token == '(':
769 772 openPar += 1
770 773 if openPar > 0:
771 774 # found the last unclosed parenthesis
772 775 break
773 776 else:
774 777 return []
775 778 # 2. Concatenate dotted names ("foo.bar" for "foo.bar(x, pa" )
776 779 ids = []
777 780 isId = re.compile(r'\w+$').match
778 781
779 782 while True:
780 783 try:
781 784 ids.append(next(iterTokens))
782 785 if not isId(ids[-1]):
783 786 ids.pop(); break
784 787 if not next(iterTokens) == '.':
785 788 break
786 789 except StopIteration:
787 790 break
788 791 # lookup the candidate callable matches either using global_matches
789 792 # or attr_matches for dotted names
790 793 if len(ids) == 1:
791 794 callableMatches = self.global_matches(ids[0])
792 795 else:
793 796 callableMatches = self.attr_matches('.'.join(ids[::-1]))
794 797 argMatches = []
795 798 for callableMatch in callableMatches:
796 799 try:
797 800 namedArgs = self._default_arguments(eval(callableMatch,
798 801 self.namespace))
799 802 except:
800 803 continue
801 804
802 805 for namedArg in namedArgs:
803 806 if namedArg.startswith(text):
804 807 argMatches.append("%s=" %namedArg)
805 808 return argMatches
806 809
807 810 def dispatch_custom_completer(self, text):
808 811 #io.rprint("Custom! '%s' %s" % (text, self.custom_completers)) # dbg
809 812 line = self.line_buffer
810 813 if not line.strip():
811 814 return None
812 815
813 816 # Create a little structure to pass all the relevant information about
814 817 # the current completion to any custom completer.
815 818 event = Bunch()
816 819 event.line = line
817 820 event.symbol = text
818 821 cmd = line.split(None,1)[0]
819 822 event.command = cmd
820 823 event.text_until_cursor = self.text_until_cursor
821 824
822 825 #print "\ncustom:{%s]\n" % event # dbg
823 826
824 827 # for foo etc, try also to find completer for %foo
825 828 if not cmd.startswith(self.magic_escape):
826 829 try_magic = self.custom_completers.s_matches(
827 830 self.magic_escape + cmd)
828 831 else:
829 832 try_magic = []
830 833
831 834 for c in itertools.chain(self.custom_completers.s_matches(cmd),
832 835 try_magic,
833 836 self.custom_completers.flat_matches(self.text_until_cursor)):
834 837 #print "try",c # dbg
835 838 try:
836 839 res = c(event)
837 840 if res:
838 841 # first, try case sensitive match
839 842 withcase = [r for r in res if r.startswith(text)]
840 843 if withcase:
841 844 return withcase
842 845 # if none, then case insensitive ones are ok too
843 846 text_low = text.lower()
844 847 return [r for r in res if r.lower().startswith(text_low)]
845 848 except TryNext:
846 849 pass
847 850
848 851 return None
849 852
850 853 def complete(self, text=None, line_buffer=None, cursor_pos=None):
851 854 """Find completions for the given text and line context.
852 855
853 856 This is called successively with state == 0, 1, 2, ... until it
854 857 returns None. The completion should begin with 'text'.
855 858
856 859 Note that both the text and the line_buffer are optional, but at least
857 860 one of them must be given.
858 861
859 862 Parameters
860 863 ----------
861 864 text : string, optional
862 865 Text to perform the completion on. If not given, the line buffer
863 866 is split using the instance's CompletionSplitter object.
864 867
865 868 line_buffer : string, optional
866 869 If not given, the completer attempts to obtain the current line
867 870 buffer via readline. This keyword allows clients which are
868 871 requesting for text completions in non-readline contexts to inform
869 872 the completer of the entire text.
870 873
871 874 cursor_pos : int, optional
872 875 Index of the cursor in the full line buffer. Should be provided by
873 876 remote frontends where kernel has no access to frontend state.
874 877
875 878 Returns
876 879 -------
877 880 text : str
878 881 Text that was actually used in the completion.
879 882
880 883 matches : list
881 884 A list of completion matches.
882 885 """
883 886 #io.rprint('\nCOMP1 %r %r %r' % (text, line_buffer, cursor_pos)) # dbg
884 887
885 888 # if the cursor position isn't given, the only sane assumption we can
886 889 # make is that it's at the end of the line (the common case)
887 890 if cursor_pos is None:
888 891 cursor_pos = len(line_buffer) if text is None else len(text)
889 892
890 893 # if text is either None or an empty string, rely on the line buffer
891 894 if not text:
892 895 text = self.splitter.split_line(line_buffer, cursor_pos)
893 896
894 897 # If no line buffer is given, assume the input text is all there was
895 898 if line_buffer is None:
896 899 line_buffer = text
897 900
898 901 self.line_buffer = line_buffer
899 902 self.text_until_cursor = self.line_buffer[:cursor_pos]
900 903 #io.rprint('COMP2 %r %r %r' % (text, line_buffer, cursor_pos)) # dbg
901 904
902 905 # Start with a clean slate of completions
903 906 self.matches[:] = []
904 907 custom_res = self.dispatch_custom_completer(text)
905 908 if custom_res is not None:
906 909 # did custom completers produce something?
907 910 self.matches = custom_res
908 911 else:
909 912 # Extend the list of completions with the results of each
910 913 # matcher, so we return results to the user from all
911 914 # namespaces.
912 915 if self.merge_completions:
913 916 self.matches = []
914 917 for matcher in self.matchers:
915 918 try:
916 919 self.matches.extend(matcher(text))
917 920 except:
918 921 # Show the ugly traceback if the matcher causes an
919 922 # exception, but do NOT crash the kernel!
920 923 sys.excepthook(*sys.exc_info())
921 924 else:
922 925 for matcher in self.matchers:
923 926 self.matches = matcher(text)
924 927 if self.matches:
925 928 break
926 929 # FIXME: we should extend our api to return a dict with completions for
927 930 # different types of objects. The rlcomplete() method could then
928 931 # simply collapse the dict into a list for readline, but we'd have
929 932 # richer completion semantics in other evironments.
930 933
931 934 # use penalize_magics_key to put magics after variables with same name
932 935 self.matches = sorted(set(self.matches), key=penalize_magics_key)
933 936
934 937 #io.rprint('COMP TEXT, MATCHES: %r, %r' % (text, self.matches)) # dbg
935 938 return text, self.matches
936 939
937 940 def rlcomplete(self, text, state):
938 941 """Return the state-th possible completion for 'text'.
939 942
940 943 This is called successively with state == 0, 1, 2, ... until it
941 944 returns None. The completion should begin with 'text'.
942 945
943 946 Parameters
944 947 ----------
945 948 text : string
946 949 Text to perform the completion on.
947 950
948 951 state : int
949 952 Counter used by readline.
950 953 """
951 954 if state==0:
952 955
953 956 self.line_buffer = line_buffer = self.readline.get_line_buffer()
954 957 cursor_pos = self.readline.get_endidx()
955 958
956 959 #io.rprint("\nRLCOMPLETE: %r %r %r" %
957 960 # (text, line_buffer, cursor_pos) ) # dbg
958 961
959 962 # if there is only a tab on a line with only whitespace, instead of
960 963 # the mostly useless 'do you want to see all million completions'
961 964 # message, just do the right thing and give the user his tab!
962 965 # Incidentally, this enables pasting of tabbed text from an editor
963 966 # (as long as autoindent is off).
964 967
965 968 # It should be noted that at least pyreadline still shows file
966 969 # completions - is there a way around it?
967 970
968 971 # don't apply this on 'dumb' terminals, such as emacs buffers, so
969 972 # we don't interfere with their own tab-completion mechanism.
970 973 if not (self.dumb_terminal or line_buffer.strip()):
971 974 self.readline.insert_text('\t')
972 975 sys.stdout.flush()
973 976 return None
974 977
975 978 # Note: debugging exceptions that may occur in completion is very
976 979 # tricky, because readline unconditionally silences them. So if
977 980 # during development you suspect a bug in the completion code, turn
978 981 # this flag on temporarily by uncommenting the second form (don't
979 982 # flip the value in the first line, as the '# dbg' marker can be
980 983 # automatically detected and is used elsewhere).
981 984 DEBUG = False
982 985 #DEBUG = True # dbg
983 986 if DEBUG:
984 987 try:
985 988 self.complete(text, line_buffer, cursor_pos)
986 989 except:
987 990 import traceback; traceback.print_exc()
988 991 else:
989 992 # The normal production version is here
990 993
991 994 # This method computes the self.matches array
992 995 self.complete(text, line_buffer, cursor_pos)
993 996
994 997 try:
995 998 return self.matches[state]
996 999 except IndexError:
997 1000 return None
@@ -1,439 +1,440 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Classes for handling input/output prompts.
3 3
4 4 Authors:
5 5
6 6 * Fernando Perez
7 7 * Brian Granger
8 8 * Thomas Kluyver
9 9 """
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Copyright (C) 2008-2011 The IPython Development Team
13 13 # Copyright (C) 2001-2007 Fernando Perez <fperez@colorado.edu>
14 14 #
15 15 # Distributed under the terms of the BSD License. The full license is in
16 16 # the file COPYING, distributed as part of this software.
17 17 #-----------------------------------------------------------------------------
18 18
19 19 #-----------------------------------------------------------------------------
20 20 # Imports
21 21 #-----------------------------------------------------------------------------
22 22
23 23 import os
24 24 import re
25 25 import socket
26 26 import sys
27 27 import time
28 28
29 29 from string import Formatter
30 30
31 31 from IPython.config.configurable import Configurable
32 32 from IPython.core import release
33 33 from IPython.utils import coloransi, py3compat
34 34 from IPython.utils.traitlets import (Unicode, Instance, Dict, Bool, Int)
35 35
36 36 #-----------------------------------------------------------------------------
37 37 # Color schemes for prompts
38 38 #-----------------------------------------------------------------------------
39 39
40 40 InputColors = coloransi.InputTermColors # just a shorthand
41 41 Colors = coloransi.TermColors # just a shorthand
42 42
43 43 color_lists = dict(normal=Colors(), inp=InputColors(), nocolor=coloransi.NoColors())
44 44
45 45 PColNoColors = coloransi.ColorScheme(
46 46 'NoColor',
47 47 in_prompt = InputColors.NoColor, # Input prompt
48 48 in_number = InputColors.NoColor, # Input prompt number
49 49 in_prompt2 = InputColors.NoColor, # Continuation prompt
50 50 in_normal = InputColors.NoColor, # color off (usu. Colors.Normal)
51 51
52 52 out_prompt = Colors.NoColor, # Output prompt
53 53 out_number = Colors.NoColor, # Output prompt number
54 54
55 55 normal = Colors.NoColor # color off (usu. Colors.Normal)
56 56 )
57 57
58 58 # make some schemes as instances so we can copy them for modification easily:
59 59 PColLinux = coloransi.ColorScheme(
60 60 'Linux',
61 61 in_prompt = InputColors.Green,
62 62 in_number = InputColors.LightGreen,
63 63 in_prompt2 = InputColors.Green,
64 64 in_normal = InputColors.Normal, # color off (usu. Colors.Normal)
65 65
66 66 out_prompt = Colors.Red,
67 67 out_number = Colors.LightRed,
68 68
69 69 normal = Colors.Normal
70 70 )
71 71
72 72 # Slightly modified Linux for light backgrounds
73 73 PColLightBG = PColLinux.copy('LightBG')
74 74
75 75 PColLightBG.colors.update(
76 76 in_prompt = InputColors.Blue,
77 77 in_number = InputColors.LightBlue,
78 78 in_prompt2 = InputColors.Blue
79 79 )
80 80
81 81 #-----------------------------------------------------------------------------
82 82 # Utilities
83 83 #-----------------------------------------------------------------------------
84 84
85 85 class LazyEvaluate(object):
86 86 """This is used for formatting strings with values that need to be updated
87 87 at that time, such as the current time or working directory."""
88 88 def __init__(self, func, *args, **kwargs):
89 89 self.func = func
90 90 self.args = args
91 91 self.kwargs = kwargs
92 92
93 93 def __call__(self, **kwargs):
94 94 self.kwargs.update(kwargs)
95 95 return self.func(*self.args, **self.kwargs)
96 96
97 97 def __str__(self):
98 98 return str(self())
99 99
100 100 def __unicode__(self):
101 101 return py3compat.unicode_type(self())
102 102
103 103 def __format__(self, format_spec):
104 104 return format(self(), format_spec)
105 105
106 106 def multiple_replace(dict, text):
107 107 """ Replace in 'text' all occurences of any key in the given
108 108 dictionary by its corresponding value. Returns the new string."""
109 109
110 110 # Function by Xavier Defrang, originally found at:
111 111 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81330
112 112
113 113 # Create a regular expression from the dictionary keys
114 114 regex = re.compile("(%s)" % "|".join(map(re.escape, dict.keys())))
115 115 # For each match, look-up corresponding value in dictionary
116 116 return regex.sub(lambda mo: dict[mo.string[mo.start():mo.end()]], text)
117 117
118 118 #-----------------------------------------------------------------------------
119 119 # Special characters that can be used in prompt templates, mainly bash-like
120 120 #-----------------------------------------------------------------------------
121 121
122 122 # If $HOME isn't defined (Windows), make it an absurd string so that it can
123 123 # never be expanded out into '~'. Basically anything which can never be a
124 124 # reasonable directory name will do, we just want the $HOME -> '~' operation
125 125 # to become a no-op. We pre-compute $HOME here so it's not done on every
126 126 # prompt call.
127 127
128 128 # FIXME:
129 129
130 130 # - This should be turned into a class which does proper namespace management,
131 131 # since the prompt specials need to be evaluated in a certain namespace.
132 132 # Currently it's just globals, which need to be managed manually by code
133 133 # below.
134 134
135 135 # - I also need to split up the color schemes from the prompt specials
136 136 # somehow. I don't have a clean design for that quite yet.
137 137
138 138 HOME = py3compat.str_to_unicode(os.environ.get("HOME","//////:::::ZZZZZ,,,~~~"))
139 139
140 140 # This is needed on FreeBSD, and maybe other systems which symlink /home to
141 141 # /usr/home, but retain the $HOME variable as pointing to /home
142 142 HOME = os.path.realpath(HOME)
143 143
144 144 # We precompute a few more strings here for the prompt_specials, which are
145 145 # fixed once ipython starts. This reduces the runtime overhead of computing
146 146 # prompt strings.
147 147 USER = py3compat.str_to_unicode(os.environ.get("USER",''))
148 148 HOSTNAME = py3compat.str_to_unicode(socket.gethostname())
149 149 HOSTNAME_SHORT = HOSTNAME.split(".")[0]
150 ROOT_SYMBOL = "#" if (os.name=='nt' or os.getuid()==0) else "$"
150
151 ROOT_SYMBOL = "#" if (os.name=='nt' or sys.platform=='cli' or os.getuid()==0) else "$"
151 152
152 153 prompt_abbreviations = {
153 154 # Prompt/history count
154 155 '%n' : '{color.number}' '{count}' '{color.prompt}',
155 156 r'\#': '{color.number}' '{count}' '{color.prompt}',
156 157 # Just the prompt counter number, WITHOUT any coloring wrappers, so users
157 158 # can get numbers displayed in whatever color they want.
158 159 r'\N': '{count}',
159 160
160 161 # Prompt/history count, with the actual digits replaced by dots. Used
161 162 # mainly in continuation prompts (prompt_in2)
162 163 r'\D': '{dots}',
163 164
164 165 # Current time
165 166 r'\T' : '{time}',
166 167 # Current working directory
167 168 r'\w': '{cwd}',
168 169 # Basename of current working directory.
169 170 # (use os.sep to make this portable across OSes)
170 171 r'\W' : '{cwd_last}',
171 172 # These X<N> are an extension to the normal bash prompts. They return
172 173 # N terms of the path, after replacing $HOME with '~'
173 174 r'\X0': '{cwd_x[0]}',
174 175 r'\X1': '{cwd_x[1]}',
175 176 r'\X2': '{cwd_x[2]}',
176 177 r'\X3': '{cwd_x[3]}',
177 178 r'\X4': '{cwd_x[4]}',
178 179 r'\X5': '{cwd_x[5]}',
179 180 # Y<N> are similar to X<N>, but they show '~' if it's the directory
180 181 # N+1 in the list. Somewhat like %cN in tcsh.
181 182 r'\Y0': '{cwd_y[0]}',
182 183 r'\Y1': '{cwd_y[1]}',
183 184 r'\Y2': '{cwd_y[2]}',
184 185 r'\Y3': '{cwd_y[3]}',
185 186 r'\Y4': '{cwd_y[4]}',
186 187 r'\Y5': '{cwd_y[5]}',
187 188 # Hostname up to first .
188 189 r'\h': HOSTNAME_SHORT,
189 190 # Full hostname
190 191 r'\H': HOSTNAME,
191 192 # Username of current user
192 193 r'\u': USER,
193 194 # Escaped '\'
194 195 '\\\\': '\\',
195 196 # Newline
196 197 r'\n': '\n',
197 198 # Carriage return
198 199 r'\r': '\r',
199 200 # Release version
200 201 r'\v': release.version,
201 202 # Root symbol ($ or #)
202 203 r'\$': ROOT_SYMBOL,
203 204 }
204 205
205 206 #-----------------------------------------------------------------------------
206 207 # More utilities
207 208 #-----------------------------------------------------------------------------
208 209
209 210 def cwd_filt(depth):
210 211 """Return the last depth elements of the current working directory.
211 212
212 213 $HOME is always replaced with '~'.
213 214 If depth==0, the full path is returned."""
214 215
215 216 cwd = py3compat.getcwd().replace(HOME,"~")
216 217 out = os.sep.join(cwd.split(os.sep)[-depth:])
217 218 return out or os.sep
218 219
219 220 def cwd_filt2(depth):
220 221 """Return the last depth elements of the current working directory.
221 222
222 223 $HOME is always replaced with '~'.
223 224 If depth==0, the full path is returned."""
224 225
225 226 full_cwd = py3compat.getcwd()
226 227 cwd = full_cwd.replace(HOME,"~").split(os.sep)
227 228 if '~' in cwd and len(cwd) == depth+1:
228 229 depth += 1
229 230 drivepart = ''
230 231 if sys.platform == 'win32' and len(cwd) > depth:
231 232 drivepart = os.path.splitdrive(full_cwd)[0]
232 233 out = drivepart + '/'.join(cwd[-depth:])
233 234
234 235 return out or os.sep
235 236
236 237 #-----------------------------------------------------------------------------
237 238 # Prompt classes
238 239 #-----------------------------------------------------------------------------
239 240
240 241 lazily_evaluate = {'time': LazyEvaluate(time.strftime, "%H:%M:%S"),
241 242 'cwd': LazyEvaluate(py3compat.getcwd),
242 243 'cwd_last': LazyEvaluate(lambda: py3compat.getcwd().split(os.sep)[-1]),
243 244 'cwd_x': [LazyEvaluate(lambda: py3compat.getcwd().replace(HOME,"~"))] +\
244 245 [LazyEvaluate(cwd_filt, x) for x in range(1,6)],
245 246 'cwd_y': [LazyEvaluate(cwd_filt2, x) for x in range(6)]
246 247 }
247 248
248 249 def _lenlastline(s):
249 250 """Get the length of the last line. More intelligent than
250 251 len(s.splitlines()[-1]).
251 252 """
252 253 if not s or s.endswith(('\n', '\r')):
253 254 return 0
254 255 return len(s.splitlines()[-1])
255 256
256 257
257 258 class UserNSFormatter(Formatter):
258 259 """A Formatter that falls back on a shell's user_ns and __builtins__ for name resolution"""
259 260 def __init__(self, shell):
260 261 self.shell = shell
261 262
262 263 def get_value(self, key, args, kwargs):
263 264 # try regular formatting first:
264 265 try:
265 266 return Formatter.get_value(self, key, args, kwargs)
266 267 except Exception:
267 268 pass
268 269 # next, look in user_ns and builtins:
269 270 for container in (self.shell.user_ns, __builtins__):
270 271 if key in container:
271 272 return container[key]
272 273 # nothing found, put error message in its place
273 274 return "<ERROR: '%s' not found>" % key
274 275
275 276
276 277 class PromptManager(Configurable):
277 278 """This is the primary interface for producing IPython's prompts."""
278 279 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
279 280
280 281 color_scheme_table = Instance(coloransi.ColorSchemeTable)
281 282 color_scheme = Unicode('Linux', config=True)
282 283 def _color_scheme_changed(self, name, new_value):
283 284 self.color_scheme_table.set_active_scheme(new_value)
284 285 for pname in ['in', 'in2', 'out', 'rewrite']:
285 286 # We need to recalculate the number of invisible characters
286 287 self.update_prompt(pname)
287 288
288 289 lazy_evaluate_fields = Dict(help="""
289 290 This maps field names used in the prompt templates to functions which
290 291 will be called when the prompt is rendered. This allows us to include
291 292 things like the current time in the prompts. Functions are only called
292 293 if they are used in the prompt.
293 294 """)
294 295 def _lazy_evaluate_fields_default(self): return lazily_evaluate.copy()
295 296
296 297 in_template = Unicode('In [\\#]: ', config=True,
297 298 help="Input prompt. '\\#' will be transformed to the prompt number")
298 299 in2_template = Unicode(' .\\D.: ', config=True,
299 300 help="Continuation prompt.")
300 301 out_template = Unicode('Out[\\#]: ', config=True,
301 302 help="Output prompt. '\\#' will be transformed to the prompt number")
302 303
303 304 justify = Bool(True, config=True, help="""
304 305 If True (default), each prompt will be right-aligned with the
305 306 preceding one.
306 307 """)
307 308
308 309 # We actually store the expanded templates here:
309 310 templates = Dict()
310 311
311 312 # The number of characters in the last prompt rendered, not including
312 313 # colour characters.
313 314 width = Int()
314 315 txtwidth = Int() # Not including right-justification
315 316
316 317 # The number of characters in each prompt which don't contribute to width
317 318 invisible_chars = Dict()
318 319 def _invisible_chars_default(self):
319 320 return {'in': 0, 'in2': 0, 'out': 0, 'rewrite':0}
320 321
321 322 def __init__(self, shell, **kwargs):
322 323 super(PromptManager, self).__init__(shell=shell, **kwargs)
323 324
324 325 # Prepare colour scheme table
325 326 self.color_scheme_table = coloransi.ColorSchemeTable([PColNoColors,
326 327 PColLinux, PColLightBG], self.color_scheme)
327 328
328 329 self._formatter = UserNSFormatter(shell)
329 330 # Prepare templates & numbers of invisible characters
330 331 self.update_prompt('in', self.in_template)
331 332 self.update_prompt('in2', self.in2_template)
332 333 self.update_prompt('out', self.out_template)
333 334 self.update_prompt('rewrite')
334 335 self.on_trait_change(self._update_prompt_trait, ['in_template',
335 336 'in2_template', 'out_template'])
336 337
337 338 def update_prompt(self, name, new_template=None):
338 339 """This is called when a prompt template is updated. It processes
339 340 abbreviations used in the prompt template (like \#) and calculates how
340 341 many invisible characters (ANSI colour escapes) the resulting prompt
341 342 contains.
342 343
343 344 It is also called for each prompt on changing the colour scheme. In both
344 345 cases, traitlets should take care of calling this automatically.
345 346 """
346 347 if new_template is not None:
347 348 self.templates[name] = multiple_replace(prompt_abbreviations, new_template)
348 349 # We count invisible characters (colour escapes) on the last line of the
349 350 # prompt, to calculate the width for lining up subsequent prompts.
350 351 invis_chars = _lenlastline(self._render(name, color=True)) - \
351 352 _lenlastline(self._render(name, color=False))
352 353 self.invisible_chars[name] = invis_chars
353 354
354 355 def _update_prompt_trait(self, traitname, new_template):
355 356 name = traitname[:-9] # Cut off '_template'
356 357 self.update_prompt(name, new_template)
357 358
358 359 def _render(self, name, color=True, **kwargs):
359 360 """Render but don't justify, or update the width or txtwidth attributes.
360 361 """
361 362 if name == 'rewrite':
362 363 return self._render_rewrite(color=color)
363 364
364 365 if color:
365 366 scheme = self.color_scheme_table.active_colors
366 367 if name=='out':
367 368 colors = color_lists['normal']
368 369 colors.number, colors.prompt, colors.normal = \
369 370 scheme.out_number, scheme.out_prompt, scheme.normal
370 371 else:
371 372 colors = color_lists['inp']
372 373 colors.number, colors.prompt, colors.normal = \
373 374 scheme.in_number, scheme.in_prompt, scheme.in_normal
374 375 if name=='in2':
375 376 colors.prompt = scheme.in_prompt2
376 377 else:
377 378 # No color
378 379 colors = color_lists['nocolor']
379 380 colors.number, colors.prompt, colors.normal = '', '', ''
380 381
381 382 count = self.shell.execution_count # Shorthand
382 383 # Build the dictionary to be passed to string formatting
383 384 fmtargs = dict(color=colors, count=count,
384 385 dots="."*len(str(count)),
385 386 width=self.width, txtwidth=self.txtwidth )
386 387 fmtargs.update(self.lazy_evaluate_fields)
387 388 fmtargs.update(kwargs)
388 389
389 390 # Prepare the prompt
390 391 prompt = colors.prompt + self.templates[name] + colors.normal
391 392
392 393 # Fill in required fields
393 394 return self._formatter.format(prompt, **fmtargs)
394 395
395 396 def _render_rewrite(self, color=True):
396 397 """Render the ---> rewrite prompt."""
397 398 if color:
398 399 scheme = self.color_scheme_table.active_colors
399 400 # We need a non-input version of these escapes
400 401 color_prompt = scheme.in_prompt.replace("\001","").replace("\002","")
401 402 color_normal = scheme.normal
402 403 else:
403 404 color_prompt, color_normal = '', ''
404 405
405 406 return color_prompt + "-> ".rjust(self.txtwidth, "-") + color_normal
406 407
407 408 def render(self, name, color=True, just=None, **kwargs):
408 409 """
409 410 Render the selected prompt.
410 411
411 412 Parameters
412 413 ----------
413 414 name : str
414 415 Which prompt to render. One of 'in', 'in2', 'out', 'rewrite'
415 416 color : bool
416 417 If True (default), include ANSI escape sequences for a coloured prompt.
417 418 just : bool
418 419 If True, justify the prompt to the width of the last prompt. The
419 420 default is stored in self.justify.
420 421 **kwargs :
421 422 Additional arguments will be passed to the string formatting operation,
422 423 so they can override the values that would otherwise fill in the
423 424 template.
424 425
425 426 Returns
426 427 -------
427 428 A string containing the rendered prompt.
428 429 """
429 430 res = self._render(name, color=color, **kwargs)
430 431
431 432 # Handle justification of prompt
432 433 invis_chars = self.invisible_chars[name] if color else 0
433 434 self.txtwidth = _lenlastline(res) - invis_chars
434 435 just = self.justify if (just is None) else just
435 436 # If the prompt spans more than one line, don't try to justify it:
436 437 if just and name != 'in' and ('\n' not in res) and ('\r' not in res):
437 438 res = res.rjust(self.width + invis_chars)
438 439 self.width = _lenlastline(res) - invis_chars
439 440 return res
@@ -1,532 +1,534 b''
1 1 # coding: utf-8
2 2 """
3 3 Inputhook management for GUI event loop integration.
4 4 """
5 5
6 6 #-----------------------------------------------------------------------------
7 7 # Copyright (C) 2008-2011 The IPython Development Team
8 8 #
9 9 # Distributed under the terms of the BSD License. The full license is in
10 10 # the file COPYING, distributed as part of this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16
17 17 try:
18 18 import ctypes
19 19 except ImportError:
20 20 ctypes = None
21 except SystemError:
22 ctypes = None
21 23 import os
22 24 import sys
23 25 from distutils.version import LooseVersion as V
24 26
25 27 from IPython.utils.warn import warn
26 28
27 29 #-----------------------------------------------------------------------------
28 30 # Constants
29 31 #-----------------------------------------------------------------------------
30 32
31 33 # Constants for identifying the GUI toolkits.
32 34 GUI_WX = 'wx'
33 35 GUI_QT = 'qt'
34 36 GUI_QT4 = 'qt4'
35 37 GUI_GTK = 'gtk'
36 38 GUI_TK = 'tk'
37 39 GUI_OSX = 'osx'
38 40 GUI_GLUT = 'glut'
39 41 GUI_PYGLET = 'pyglet'
40 42 GUI_GTK3 = 'gtk3'
41 43 GUI_NONE = 'none' # i.e. disable
42 44
43 45 #-----------------------------------------------------------------------------
44 46 # Utilities
45 47 #-----------------------------------------------------------------------------
46 48
47 49 def _stdin_ready_posix():
48 50 """Return True if there's something to read on stdin (posix version)."""
49 51 infds, outfds, erfds = select.select([sys.stdin],[],[],0)
50 52 return bool(infds)
51 53
52 54 def _stdin_ready_nt():
53 55 """Return True if there's something to read on stdin (nt version)."""
54 56 return msvcrt.kbhit()
55 57
56 58 def _stdin_ready_other():
57 59 """Return True, assuming there's something to read on stdin."""
58 60 return True #
59 61
60 62
61 63 def _ignore_CTRL_C_posix():
62 64 """Ignore CTRL+C (SIGINT)."""
63 65 signal.signal(signal.SIGINT, signal.SIG_IGN)
64 66
65 67 def _allow_CTRL_C_posix():
66 68 """Take CTRL+C into account (SIGINT)."""
67 69 signal.signal(signal.SIGINT, signal.default_int_handler)
68 70
69 71 def _ignore_CTRL_C_other():
70 72 """Ignore CTRL+C (not implemented)."""
71 73 pass
72 74
73 75 def _allow_CTRL_C_other():
74 76 """Take CTRL+C into account (not implemented)."""
75 77 pass
76 78
77 79 if os.name == 'posix':
78 80 import select
79 81 import signal
80 82 stdin_ready = _stdin_ready_posix
81 83 ignore_CTRL_C = _ignore_CTRL_C_posix
82 84 allow_CTRL_C = _allow_CTRL_C_posix
83 85 elif os.name == 'nt':
84 86 import msvcrt
85 87 stdin_ready = _stdin_ready_nt
86 88 ignore_CTRL_C = _ignore_CTRL_C_other
87 89 allow_CTRL_C = _allow_CTRL_C_other
88 90 else:
89 91 stdin_ready = _stdin_ready_other
90 92 ignore_CTRL_C = _ignore_CTRL_C_other
91 93 allow_CTRL_C = _allow_CTRL_C_other
92 94
93 95
94 96 #-----------------------------------------------------------------------------
95 97 # Main InputHookManager class
96 98 #-----------------------------------------------------------------------------
97 99
98 100
99 101 class InputHookManager(object):
100 102 """Manage PyOS_InputHook for different GUI toolkits.
101 103
102 104 This class installs various hooks under ``PyOSInputHook`` to handle
103 105 GUI event loop integration.
104 106 """
105 107
106 108 def __init__(self):
107 109 if ctypes is None:
108 110 warn("IPython GUI event loop requires ctypes, %gui will not be available")
109 111 return
110 112 self.PYFUNC = ctypes.PYFUNCTYPE(ctypes.c_int)
111 113 self._apps = {}
112 114 self._reset()
113 115
114 116 def _reset(self):
115 117 self._callback_pyfunctype = None
116 118 self._callback = None
117 119 self._installed = False
118 120 self._current_gui = None
119 121
120 122 def get_pyos_inputhook(self):
121 123 """Return the current PyOS_InputHook as a ctypes.c_void_p."""
122 124 return ctypes.c_void_p.in_dll(ctypes.pythonapi,"PyOS_InputHook")
123 125
124 126 def get_pyos_inputhook_as_func(self):
125 127 """Return the current PyOS_InputHook as a ctypes.PYFUNCYPE."""
126 128 return self.PYFUNC.in_dll(ctypes.pythonapi,"PyOS_InputHook")
127 129
128 130 def set_inputhook(self, callback):
129 131 """Set PyOS_InputHook to callback and return the previous one."""
130 132 # On platforms with 'readline' support, it's all too likely to
131 133 # have a KeyboardInterrupt signal delivered *even before* an
132 134 # initial ``try:`` clause in the callback can be executed, so
133 135 # we need to disable CTRL+C in this situation.
134 136 ignore_CTRL_C()
135 137 self._callback = callback
136 138 self._callback_pyfunctype = self.PYFUNC(callback)
137 139 pyos_inputhook_ptr = self.get_pyos_inputhook()
138 140 original = self.get_pyos_inputhook_as_func()
139 141 pyos_inputhook_ptr.value = \
140 142 ctypes.cast(self._callback_pyfunctype, ctypes.c_void_p).value
141 143 self._installed = True
142 144 return original
143 145
144 146 def clear_inputhook(self, app=None):
145 147 """Set PyOS_InputHook to NULL and return the previous one.
146 148
147 149 Parameters
148 150 ----------
149 151 app : optional, ignored
150 152 This parameter is allowed only so that clear_inputhook() can be
151 153 called with a similar interface as all the ``enable_*`` methods. But
152 154 the actual value of the parameter is ignored. This uniform interface
153 155 makes it easier to have user-level entry points in the main IPython
154 156 app like :meth:`enable_gui`."""
155 157 pyos_inputhook_ptr = self.get_pyos_inputhook()
156 158 original = self.get_pyos_inputhook_as_func()
157 159 pyos_inputhook_ptr.value = ctypes.c_void_p(None).value
158 160 allow_CTRL_C()
159 161 self._reset()
160 162 return original
161 163
162 164 def clear_app_refs(self, gui=None):
163 165 """Clear IPython's internal reference to an application instance.
164 166
165 167 Whenever we create an app for a user on qt4 or wx, we hold a
166 168 reference to the app. This is needed because in some cases bad things
167 169 can happen if a user doesn't hold a reference themselves. This
168 170 method is provided to clear the references we are holding.
169 171
170 172 Parameters
171 173 ----------
172 174 gui : None or str
173 175 If None, clear all app references. If ('wx', 'qt4') clear
174 176 the app for that toolkit. References are not held for gtk or tk
175 177 as those toolkits don't have the notion of an app.
176 178 """
177 179 if gui is None:
178 180 self._apps = {}
179 181 elif gui in self._apps:
180 182 del self._apps[gui]
181 183
182 184 def enable_wx(self, app=None):
183 185 """Enable event loop integration with wxPython.
184 186
185 187 Parameters
186 188 ----------
187 189 app : WX Application, optional.
188 190 Running application to use. If not given, we probe WX for an
189 191 existing application object, and create a new one if none is found.
190 192
191 193 Notes
192 194 -----
193 195 This methods sets the ``PyOS_InputHook`` for wxPython, which allows
194 196 the wxPython to integrate with terminal based applications like
195 197 IPython.
196 198
197 199 If ``app`` is not given we probe for an existing one, and return it if
198 200 found. If no existing app is found, we create an :class:`wx.App` as
199 201 follows::
200 202
201 203 import wx
202 204 app = wx.App(redirect=False, clearSigInt=False)
203 205 """
204 206 import wx
205 207
206 208 wx_version = V(wx.__version__).version
207 209
208 210 if wx_version < [2, 8]:
209 211 raise ValueError("requires wxPython >= 2.8, but you have %s" % wx.__version__)
210 212
211 213 from IPython.lib.inputhookwx import inputhook_wx
212 214 self.set_inputhook(inputhook_wx)
213 215 self._current_gui = GUI_WX
214 216 import wx
215 217 if app is None:
216 218 app = wx.GetApp()
217 219 if app is None:
218 220 app = wx.App(redirect=False, clearSigInt=False)
219 221 app._in_event_loop = True
220 222 self._apps[GUI_WX] = app
221 223 return app
222 224
223 225 def disable_wx(self):
224 226 """Disable event loop integration with wxPython.
225 227
226 228 This merely sets PyOS_InputHook to NULL.
227 229 """
228 230 if GUI_WX in self._apps:
229 231 self._apps[GUI_WX]._in_event_loop = False
230 232 self.clear_inputhook()
231 233
232 234 def enable_qt4(self, app=None):
233 235 """Enable event loop integration with PyQt4.
234 236
235 237 Parameters
236 238 ----------
237 239 app : Qt Application, optional.
238 240 Running application to use. If not given, we probe Qt for an
239 241 existing application object, and create a new one if none is found.
240 242
241 243 Notes
242 244 -----
243 245 This methods sets the PyOS_InputHook for PyQt4, which allows
244 246 the PyQt4 to integrate with terminal based applications like
245 247 IPython.
246 248
247 249 If ``app`` is not given we probe for an existing one, and return it if
248 250 found. If no existing app is found, we create an :class:`QApplication`
249 251 as follows::
250 252
251 253 from PyQt4 import QtCore
252 254 app = QtGui.QApplication(sys.argv)
253 255 """
254 256 from IPython.lib.inputhookqt4 import create_inputhook_qt4
255 257 app, inputhook_qt4 = create_inputhook_qt4(self, app)
256 258 self.set_inputhook(inputhook_qt4)
257 259
258 260 self._current_gui = GUI_QT4
259 261 app._in_event_loop = True
260 262 self._apps[GUI_QT4] = app
261 263 return app
262 264
263 265 def disable_qt4(self):
264 266 """Disable event loop integration with PyQt4.
265 267
266 268 This merely sets PyOS_InputHook to NULL.
267 269 """
268 270 if GUI_QT4 in self._apps:
269 271 self._apps[GUI_QT4]._in_event_loop = False
270 272 self.clear_inputhook()
271 273
272 274 def enable_gtk(self, app=None):
273 275 """Enable event loop integration with PyGTK.
274 276
275 277 Parameters
276 278 ----------
277 279 app : ignored
278 280 Ignored, it's only a placeholder to keep the call signature of all
279 281 gui activation methods consistent, which simplifies the logic of
280 282 supporting magics.
281 283
282 284 Notes
283 285 -----
284 286 This methods sets the PyOS_InputHook for PyGTK, which allows
285 287 the PyGTK to integrate with terminal based applications like
286 288 IPython.
287 289 """
288 290 import gtk
289 291 try:
290 292 gtk.set_interactive(True)
291 293 self._current_gui = GUI_GTK
292 294 except AttributeError:
293 295 # For older versions of gtk, use our own ctypes version
294 296 from IPython.lib.inputhookgtk import inputhook_gtk
295 297 self.set_inputhook(inputhook_gtk)
296 298 self._current_gui = GUI_GTK
297 299
298 300 def disable_gtk(self):
299 301 """Disable event loop integration with PyGTK.
300 302
301 303 This merely sets PyOS_InputHook to NULL.
302 304 """
303 305 self.clear_inputhook()
304 306
305 307 def enable_tk(self, app=None):
306 308 """Enable event loop integration with Tk.
307 309
308 310 Parameters
309 311 ----------
310 312 app : toplevel :class:`Tkinter.Tk` widget, optional.
311 313 Running toplevel widget to use. If not given, we probe Tk for an
312 314 existing one, and create a new one if none is found.
313 315
314 316 Notes
315 317 -----
316 318 If you have already created a :class:`Tkinter.Tk` object, the only
317 319 thing done by this method is to register with the
318 320 :class:`InputHookManager`, since creating that object automatically
319 321 sets ``PyOS_InputHook``.
320 322 """
321 323 self._current_gui = GUI_TK
322 324 if app is None:
323 325 try:
324 326 from tkinter import Tk # Py 3
325 327 except ImportError:
326 328 from Tkinter import Tk # Py 2
327 329 app = Tk()
328 330 app.withdraw()
329 331 self._apps[GUI_TK] = app
330 332 return app
331 333
332 334 def disable_tk(self):
333 335 """Disable event loop integration with Tkinter.
334 336
335 337 This merely sets PyOS_InputHook to NULL.
336 338 """
337 339 self.clear_inputhook()
338 340
339 341
340 342 def enable_glut(self, app=None):
341 343 """ Enable event loop integration with GLUT.
342 344
343 345 Parameters
344 346 ----------
345 347
346 348 app : ignored
347 349 Ignored, it's only a placeholder to keep the call signature of all
348 350 gui activation methods consistent, which simplifies the logic of
349 351 supporting magics.
350 352
351 353 Notes
352 354 -----
353 355
354 356 This methods sets the PyOS_InputHook for GLUT, which allows the GLUT to
355 357 integrate with terminal based applications like IPython. Due to GLUT
356 358 limitations, it is currently not possible to start the event loop
357 359 without first creating a window. You should thus not create another
358 360 window but use instead the created one. See 'gui-glut.py' in the
359 361 docs/examples/lib directory.
360 362
361 363 The default screen mode is set to:
362 364 glut.GLUT_DOUBLE | glut.GLUT_RGBA | glut.GLUT_DEPTH
363 365 """
364 366
365 367 import OpenGL.GLUT as glut
366 368 from IPython.lib.inputhookglut import glut_display_mode, \
367 369 glut_close, glut_display, \
368 370 glut_idle, inputhook_glut
369 371
370 372 if GUI_GLUT not in self._apps:
371 373 glut.glutInit( sys.argv )
372 374 glut.glutInitDisplayMode( glut_display_mode )
373 375 # This is specific to freeglut
374 376 if bool(glut.glutSetOption):
375 377 glut.glutSetOption( glut.GLUT_ACTION_ON_WINDOW_CLOSE,
376 378 glut.GLUT_ACTION_GLUTMAINLOOP_RETURNS )
377 379 glut.glutCreateWindow( sys.argv[0] )
378 380 glut.glutReshapeWindow( 1, 1 )
379 381 glut.glutHideWindow( )
380 382 glut.glutWMCloseFunc( glut_close )
381 383 glut.glutDisplayFunc( glut_display )
382 384 glut.glutIdleFunc( glut_idle )
383 385 else:
384 386 glut.glutWMCloseFunc( glut_close )
385 387 glut.glutDisplayFunc( glut_display )
386 388 glut.glutIdleFunc( glut_idle)
387 389 self.set_inputhook( inputhook_glut )
388 390 self._current_gui = GUI_GLUT
389 391 self._apps[GUI_GLUT] = True
390 392
391 393
392 394 def disable_glut(self):
393 395 """Disable event loop integration with glut.
394 396
395 397 This sets PyOS_InputHook to NULL and set the display function to a
396 398 dummy one and set the timer to a dummy timer that will be triggered
397 399 very far in the future.
398 400 """
399 401 import OpenGL.GLUT as glut
400 402 from glut_support import glutMainLoopEvent
401 403
402 404 glut.glutHideWindow() # This is an event to be processed below
403 405 glutMainLoopEvent()
404 406 self.clear_inputhook()
405 407
406 408 def enable_pyglet(self, app=None):
407 409 """Enable event loop integration with pyglet.
408 410
409 411 Parameters
410 412 ----------
411 413 app : ignored
412 414 Ignored, it's only a placeholder to keep the call signature of all
413 415 gui activation methods consistent, which simplifies the logic of
414 416 supporting magics.
415 417
416 418 Notes
417 419 -----
418 420 This methods sets the ``PyOS_InputHook`` for pyglet, which allows
419 421 pyglet to integrate with terminal based applications like
420 422 IPython.
421 423
422 424 """
423 425 from IPython.lib.inputhookpyglet import inputhook_pyglet
424 426 self.set_inputhook(inputhook_pyglet)
425 427 self._current_gui = GUI_PYGLET
426 428 return app
427 429
428 430 def disable_pyglet(self):
429 431 """Disable event loop integration with pyglet.
430 432
431 433 This merely sets PyOS_InputHook to NULL.
432 434 """
433 435 self.clear_inputhook()
434 436
435 437 def enable_gtk3(self, app=None):
436 438 """Enable event loop integration with Gtk3 (gir bindings).
437 439
438 440 Parameters
439 441 ----------
440 442 app : ignored
441 443 Ignored, it's only a placeholder to keep the call signature of all
442 444 gui activation methods consistent, which simplifies the logic of
443 445 supporting magics.
444 446
445 447 Notes
446 448 -----
447 449 This methods sets the PyOS_InputHook for Gtk3, which allows
448 450 the Gtk3 to integrate with terminal based applications like
449 451 IPython.
450 452 """
451 453 from IPython.lib.inputhookgtk3 import inputhook_gtk3
452 454 self.set_inputhook(inputhook_gtk3)
453 455 self._current_gui = GUI_GTK
454 456
455 457 def disable_gtk3(self):
456 458 """Disable event loop integration with PyGTK.
457 459
458 460 This merely sets PyOS_InputHook to NULL.
459 461 """
460 462 self.clear_inputhook()
461 463
462 464 def current_gui(self):
463 465 """Return a string indicating the currently active GUI or None."""
464 466 return self._current_gui
465 467
466 468 inputhook_manager = InputHookManager()
467 469
468 470 enable_wx = inputhook_manager.enable_wx
469 471 disable_wx = inputhook_manager.disable_wx
470 472 enable_qt4 = inputhook_manager.enable_qt4
471 473 disable_qt4 = inputhook_manager.disable_qt4
472 474 enable_gtk = inputhook_manager.enable_gtk
473 475 disable_gtk = inputhook_manager.disable_gtk
474 476 enable_tk = inputhook_manager.enable_tk
475 477 disable_tk = inputhook_manager.disable_tk
476 478 enable_glut = inputhook_manager.enable_glut
477 479 disable_glut = inputhook_manager.disable_glut
478 480 enable_pyglet = inputhook_manager.enable_pyglet
479 481 disable_pyglet = inputhook_manager.disable_pyglet
480 482 enable_gtk3 = inputhook_manager.enable_gtk3
481 483 disable_gtk3 = inputhook_manager.disable_gtk3
482 484 clear_inputhook = inputhook_manager.clear_inputhook
483 485 set_inputhook = inputhook_manager.set_inputhook
484 486 current_gui = inputhook_manager.current_gui
485 487 clear_app_refs = inputhook_manager.clear_app_refs
486 488
487 489 guis = {None: clear_inputhook,
488 490 GUI_NONE: clear_inputhook,
489 491 GUI_OSX: lambda app=False: None,
490 492 GUI_TK: enable_tk,
491 493 GUI_GTK: enable_gtk,
492 494 GUI_WX: enable_wx,
493 495 GUI_QT: enable_qt4, # qt3 not supported
494 496 GUI_QT4: enable_qt4,
495 497 GUI_GLUT: enable_glut,
496 498 GUI_PYGLET: enable_pyglet,
497 499 GUI_GTK3: enable_gtk3,
498 500 }
499 501
500 502
501 503 # Convenience function to switch amongst them
502 504 def enable_gui(gui=None, app=None):
503 505 """Switch amongst GUI input hooks by name.
504 506
505 507 This is just a utility wrapper around the methods of the InputHookManager
506 508 object.
507 509
508 510 Parameters
509 511 ----------
510 512 gui : optional, string or None
511 513 If None (or 'none'), clears input hook, otherwise it must be one
512 514 of the recognized GUI names (see ``GUI_*`` constants in module).
513 515
514 516 app : optional, existing application object.
515 517 For toolkits that have the concept of a global app, you can supply an
516 518 existing one. If not given, the toolkit will be probed for one, and if
517 519 none is found, a new one will be created. Note that GTK does not have
518 520 this concept, and passing an app if ``gui=="GTK"`` will raise an error.
519 521
520 522 Returns
521 523 -------
522 524 The output of the underlying gui switch routine, typically the actual
523 525 PyOS_InputHook wrapper object or the GUI toolkit app created, if there was
524 526 one.
525 527 """
526 528 try:
527 529 gui_hook = guis[gui]
528 530 except KeyError:
529 531 e = "Invalid GUI request %r, valid ones are:%s" % (gui, guis.keys())
530 532 raise ValueError(e)
531 533 return gui_hook(app)
532 534
@@ -1,262 +1,262 b''
1 1 # encoding: utf-8
2 2 """
3 3 IO related utilities.
4 4 """
5 5
6 6 #-----------------------------------------------------------------------------
7 7 # Copyright (C) 2008-2011 The IPython Development Team
8 8 #
9 9 # Distributed under the terms of the BSD License. The full license is in
10 10 # the file COPYING, distributed as part of this software.
11 11 #-----------------------------------------------------------------------------
12 12 from __future__ import print_function
13 13 from __future__ import absolute_import
14 14
15 15 #-----------------------------------------------------------------------------
16 16 # Imports
17 17 #-----------------------------------------------------------------------------
18 18 import codecs
19 19 import os
20 20 import sys
21 21 import tempfile
22 22 from .capture import CapturedIO, capture_output
23 23 from .py3compat import string_types, input, PY3
24 24
25 25 #-----------------------------------------------------------------------------
26 26 # Code
27 27 #-----------------------------------------------------------------------------
28 28
29 29
30 30 class IOStream:
31 31
32 32 def __init__(self,stream, fallback=None):
33 33 if not hasattr(stream,'write') or not hasattr(stream,'flush'):
34 34 if fallback is not None:
35 35 stream = fallback
36 36 else:
37 37 raise ValueError("fallback required, but not specified")
38 38 self.stream = stream
39 39 self._swrite = stream.write
40 40
41 41 # clone all methods not overridden:
42 42 def clone(meth):
43 43 return not hasattr(self, meth) and not meth.startswith('_')
44 44 for meth in filter(clone, dir(stream)):
45 45 setattr(self, meth, getattr(stream, meth))
46 46
47 47 def __repr__(self):
48 48 cls = self.__class__
49 49 tpl = '{mod}.{cls}({args})'
50 50 return tpl.format(mod=cls.__module__, cls=cls.__name__, args=self.stream)
51 51
52 52 def write(self,data):
53 53 try:
54 54 self._swrite(data)
55 55 except:
56 56 try:
57 57 # print handles some unicode issues which may trip a plain
58 58 # write() call. Emulate write() by using an empty end
59 59 # argument.
60 60 print(data, end='', file=self.stream)
61 61 except:
62 62 # if we get here, something is seriously broken.
63 63 print('ERROR - failed to write data to stream:', self.stream,
64 64 file=sys.stderr)
65 65
66 66 def writelines(self, lines):
67 67 if isinstance(lines, string_types):
68 68 lines = [lines]
69 69 for line in lines:
70 70 self.write(line)
71 71
72 72 # This class used to have a writeln method, but regular files and streams
73 73 # in Python don't have this method. We need to keep this completely
74 74 # compatible so we removed it.
75 75
76 76 @property
77 77 def closed(self):
78 78 return self.stream.closed
79 79
80 80 def close(self):
81 81 pass
82 82
83 83 # setup stdin/stdout/stderr to sys.stdin/sys.stdout/sys.stderr
84 devnull = open(os.devnull, 'a')
84 devnull = open(os.devnull, 'w')
85 85 stdin = IOStream(sys.stdin, fallback=devnull)
86 86 stdout = IOStream(sys.stdout, fallback=devnull)
87 87 stderr = IOStream(sys.stderr, fallback=devnull)
88 88
89 89 class IOTerm:
90 90 """ Term holds the file or file-like objects for handling I/O operations.
91 91
92 92 These are normally just sys.stdin, sys.stdout and sys.stderr but for
93 93 Windows they can can replaced to allow editing the strings before they are
94 94 displayed."""
95 95
96 96 # In the future, having IPython channel all its I/O operations through
97 97 # this class will make it easier to embed it into other environments which
98 98 # are not a normal terminal (such as a GUI-based shell)
99 99 def __init__(self, stdin=None, stdout=None, stderr=None):
100 100 mymodule = sys.modules[__name__]
101 101 self.stdin = IOStream(stdin, mymodule.stdin)
102 102 self.stdout = IOStream(stdout, mymodule.stdout)
103 103 self.stderr = IOStream(stderr, mymodule.stderr)
104 104
105 105
106 106 class Tee(object):
107 107 """A class to duplicate an output stream to stdout/err.
108 108
109 109 This works in a manner very similar to the Unix 'tee' command.
110 110
111 111 When the object is closed or deleted, it closes the original file given to
112 112 it for duplication.
113 113 """
114 114 # Inspired by:
115 115 # http://mail.python.org/pipermail/python-list/2007-May/442737.html
116 116
117 117 def __init__(self, file_or_name, mode="w", channel='stdout'):
118 118 """Construct a new Tee object.
119 119
120 120 Parameters
121 121 ----------
122 122 file_or_name : filename or open filehandle (writable)
123 123 File that will be duplicated
124 124
125 125 mode : optional, valid mode for open().
126 126 If a filename was give, open with this mode.
127 127
128 128 channel : str, one of ['stdout', 'stderr']
129 129 """
130 130 if channel not in ['stdout', 'stderr']:
131 131 raise ValueError('Invalid channel spec %s' % channel)
132 132
133 133 if hasattr(file_or_name, 'write') and hasattr(file_or_name, 'seek'):
134 134 self.file = file_or_name
135 135 else:
136 136 self.file = open(file_or_name, mode)
137 137 self.channel = channel
138 138 self.ostream = getattr(sys, channel)
139 139 setattr(sys, channel, self)
140 140 self._closed = False
141 141
142 142 def close(self):
143 143 """Close the file and restore the channel."""
144 144 self.flush()
145 145 setattr(sys, self.channel, self.ostream)
146 146 self.file.close()
147 147 self._closed = True
148 148
149 149 def write(self, data):
150 150 """Write data to both channels."""
151 151 self.file.write(data)
152 152 self.ostream.write(data)
153 153 self.ostream.flush()
154 154
155 155 def flush(self):
156 156 """Flush both channels."""
157 157 self.file.flush()
158 158 self.ostream.flush()
159 159
160 160 def __del__(self):
161 161 if not self._closed:
162 162 self.close()
163 163
164 164
165 165 def ask_yes_no(prompt, default=None, interrupt=None):
166 166 """Asks a question and returns a boolean (y/n) answer.
167 167
168 168 If default is given (one of 'y','n'), it is used if the user input is
169 169 empty. If interrupt is given (one of 'y','n'), it is used if the user
170 170 presses Ctrl-C. Otherwise the question is repeated until an answer is
171 171 given.
172 172
173 173 An EOF is treated as the default answer. If there is no default, an
174 174 exception is raised to prevent infinite loops.
175 175
176 176 Valid answers are: y/yes/n/no (match is not case sensitive)."""
177 177
178 178 answers = {'y':True,'n':False,'yes':True,'no':False}
179 179 ans = None
180 180 while ans not in answers.keys():
181 181 try:
182 182 ans = input(prompt+' ').lower()
183 183 if not ans: # response was an empty string
184 184 ans = default
185 185 except KeyboardInterrupt:
186 186 if interrupt:
187 187 ans = interrupt
188 188 except EOFError:
189 189 if default in answers.keys():
190 190 ans = default
191 191 print()
192 192 else:
193 193 raise
194 194
195 195 return answers[ans]
196 196
197 197
198 198 def temp_pyfile(src, ext='.py'):
199 199 """Make a temporary python file, return filename and filehandle.
200 200
201 201 Parameters
202 202 ----------
203 203 src : string or list of strings (no need for ending newlines if list)
204 204 Source code to be written to the file.
205 205
206 206 ext : optional, string
207 207 Extension for the generated file.
208 208
209 209 Returns
210 210 -------
211 211 (filename, open filehandle)
212 212 It is the caller's responsibility to close the open file and unlink it.
213 213 """
214 214 fname = tempfile.mkstemp(ext)[1]
215 215 f = open(fname,'w')
216 216 f.write(src)
217 217 f.flush()
218 218 return fname, f
219 219
220 220
221 221 def raw_print(*args, **kw):
222 222 """Raw print to sys.__stdout__, otherwise identical interface to print()."""
223 223
224 224 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
225 225 file=sys.__stdout__)
226 226 sys.__stdout__.flush()
227 227
228 228
229 229 def raw_print_err(*args, **kw):
230 230 """Raw print to sys.__stderr__, otherwise identical interface to print()."""
231 231
232 232 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
233 233 file=sys.__stderr__)
234 234 sys.__stderr__.flush()
235 235
236 236
237 237 # Short aliases for quick debugging, do NOT use these in production code.
238 238 rprint = raw_print
239 239 rprinte = raw_print_err
240 240
241 241 def unicode_std_stream(stream='stdout'):
242 242 u"""Get a wrapper to write unicode to stdout/stderr as UTF-8.
243 243
244 244 This ignores environment variables and default encodings, to reliably write
245 245 unicode to stdout or stderr.
246 246
247 247 ::
248 248
249 249 unicode_std_stream().write(u'Ε‚@e¢ŧ←')
250 250 """
251 251 assert stream in ('stdout', 'stderr')
252 252 stream = getattr(sys, stream)
253 253 if PY3:
254 254 try:
255 255 stream_b = stream.buffer
256 256 except AttributeError:
257 257 # sys.stdout has been replaced - use it directly
258 258 return stream
259 259 else:
260 260 stream_b = stream
261 261
262 262 return codecs.getwriter('utf-8')(stream_b)
@@ -1,123 +1,124 b''
1 1 # encoding: utf-8
2 2 """
3 3 Utilities for working with external processes.
4 4 """
5 5
6 6 #-----------------------------------------------------------------------------
7 7 # Copyright (C) 2008-2011 The IPython Development Team
8 8 #
9 9 # Distributed under the terms of the BSD License. The full license is in
10 10 # the file COPYING, distributed as part of this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16 from __future__ import print_function
17 17
18 18 # Stdlib
19 19 import os
20 20 import sys
21 21 import shlex
22 22
23 23 # Our own
24 24 if sys.platform == 'win32':
25 from ._process_win32 import _find_cmd, system, getoutput, AvoidUNCPath, arg_split
25 from ._process_win32 import _find_cmd, system, getoutput, arg_split
26 elif sys.platform == 'cli':
27 from ._process_cli import _find_cmd, system, getoutput, arg_split
26 28 else:
27 29 from ._process_posix import _find_cmd, system, getoutput, arg_split
28 30
29
30 31 from ._process_common import getoutputerror, get_output_error_code, process_handler
31 32 from . import py3compat
32 33
33 34 #-----------------------------------------------------------------------------
34 35 # Code
35 36 #-----------------------------------------------------------------------------
36 37
37 38
38 39 class FindCmdError(Exception):
39 40 pass
40 41
41 42
42 43 def find_cmd(cmd):
43 44 """Find absolute path to executable cmd in a cross platform manner.
44 45
45 46 This function tries to determine the full path to a command line program
46 47 using `which` on Unix/Linux/OS X and `win32api` on Windows. Most of the
47 48 time it will use the version that is first on the users `PATH`.
48 49
49 50 Warning, don't use this to find IPython command line programs as there
50 51 is a risk you will find the wrong one. Instead find those using the
51 52 following code and looking for the application itself::
52 53
53 54 from IPython.utils.path import get_ipython_module_path
54 55 from IPython.utils.process import pycmd2argv
55 56 argv = pycmd2argv(get_ipython_module_path('IPython.terminal.ipapp'))
56 57
57 58 Parameters
58 59 ----------
59 60 cmd : str
60 61 The command line program to look for.
61 62 """
62 63 try:
63 64 path = _find_cmd(cmd).rstrip()
64 65 except OSError:
65 66 raise FindCmdError('command could not be found: %s' % cmd)
66 67 # which returns empty if not found
67 68 if path == '':
68 69 raise FindCmdError('command could not be found: %s' % cmd)
69 70 return os.path.abspath(path)
70 71
71 72
72 73 def is_cmd_found(cmd):
73 74 """Check whether executable `cmd` exists or not and return a bool."""
74 75 try:
75 76 find_cmd(cmd)
76 77 return True
77 78 except FindCmdError:
78 79 return False
79 80
80 81
81 82 def pycmd2argv(cmd):
82 83 r"""Take the path of a python command and return a list (argv-style).
83 84
84 85 This only works on Python based command line programs and will find the
85 86 location of the ``python`` executable using ``sys.executable`` to make
86 87 sure the right version is used.
87 88
88 89 For a given path ``cmd``, this returns [cmd] if cmd's extension is .exe,
89 90 .com or .bat, and [, cmd] otherwise.
90 91
91 92 Parameters
92 93 ----------
93 94 cmd : string
94 95 The path of the command.
95 96
96 97 Returns
97 98 -------
98 99 argv-style list.
99 100 """
100 101 ext = os.path.splitext(cmd)[1]
101 102 if ext in ['.exe', '.com', '.bat']:
102 103 return [cmd]
103 104 else:
104 105 return [sys.executable, cmd]
105 106
106 107
107 108 def abbrev_cwd():
108 109 """ Return abbreviated version of cwd, e.g. d:mydir """
109 110 cwd = py3compat.getcwd().replace('\\','/')
110 111 drivepart = ''
111 112 tail = cwd
112 113 if sys.platform == 'win32':
113 114 if len(cwd) < 4:
114 115 return cwd
115 116 drivepart,tail = os.path.splitdrive(cwd)
116 117
117 118
118 119 parts = tail.split('/')
119 120 if len(parts) > 2:
120 121 tail = '/'.join(parts[-2:])
121 122
122 123 return (drivepart + (
123 124 cwd == '/' and '/' or tail))
General Comments 0
You need to be logged in to leave comments. Login now