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