Show More
@@ -1,263 +1,263 | |||||
1 | # encoding: utf-8 |
|
1 | # encoding: utf-8 | |
2 | """ |
|
2 | """ | |
3 | System command aliases. |
|
3 | System command aliases. | |
4 |
|
4 | |||
5 | Authors: |
|
5 | Authors: | |
6 |
|
6 | |||
7 | * Fernando Perez |
|
7 | * Fernando Perez | |
8 | * Brian Granger |
|
8 | * Brian Granger | |
9 | """ |
|
9 | """ | |
10 |
|
10 | |||
11 | #----------------------------------------------------------------------------- |
|
11 | #----------------------------------------------------------------------------- | |
12 | # Copyright (C) 2008-2010 The IPython Development Team |
|
12 | # Copyright (C) 2008-2010 The IPython Development Team | |
13 | # |
|
13 | # | |
14 | # Distributed under the terms of the BSD License. |
|
14 | # Distributed under the terms of the BSD License. | |
15 | # |
|
15 | # | |
16 | # The full license is in the file COPYING.txt, distributed with this software. |
|
16 | # The full license is in the file COPYING.txt, distributed with this software. | |
17 | #----------------------------------------------------------------------------- |
|
17 | #----------------------------------------------------------------------------- | |
18 |
|
18 | |||
19 | #----------------------------------------------------------------------------- |
|
19 | #----------------------------------------------------------------------------- | |
20 | # Imports |
|
20 | # Imports | |
21 | #----------------------------------------------------------------------------- |
|
21 | #----------------------------------------------------------------------------- | |
22 |
|
22 | |||
23 | import __builtin__ |
|
23 | import __builtin__ | |
24 | import keyword |
|
24 | import keyword | |
25 | import os |
|
25 | import os | |
26 | import re |
|
26 | import re | |
27 | import sys |
|
27 | import sys | |
28 |
|
28 | |||
29 | from IPython.config.configurable import Configurable |
|
29 | from IPython.config.configurable import Configurable | |
30 | from IPython.core.splitinput import split_user_input |
|
30 | from IPython.core.splitinput import split_user_input | |
31 |
|
31 | |||
32 | from IPython.utils.traitlets import List, Instance |
|
32 | from IPython.utils.traitlets import List, Instance | |
33 | from IPython.utils.autoattr import auto_attr |
|
33 | from IPython.utils.autoattr import auto_attr | |
34 | from IPython.utils.warn import warn, error |
|
34 | from IPython.utils.warn import warn, error | |
35 |
|
35 | |||
36 | #----------------------------------------------------------------------------- |
|
36 | #----------------------------------------------------------------------------- | |
37 | # Utilities |
|
37 | # Utilities | |
38 | #----------------------------------------------------------------------------- |
|
38 | #----------------------------------------------------------------------------- | |
39 |
|
39 | |||
40 | # This is used as the pattern for calls to split_user_input. |
|
40 | # This is used as the pattern for calls to split_user_input. | |
41 |
shell_line_split = re.compile(r'^(\s*)(\S |
|
41 | shell_line_split = re.compile(r'^(\s*)()(\S+)(.*$)') | |
42 |
|
42 | |||
43 | def default_aliases(): |
|
43 | def default_aliases(): | |
44 | """Return list of shell aliases to auto-define. |
|
44 | """Return list of shell aliases to auto-define. | |
45 | """ |
|
45 | """ | |
46 | # Note: the aliases defined here should be safe to use on a kernel |
|
46 | # Note: the aliases defined here should be safe to use on a kernel | |
47 | # regardless of what frontend it is attached to. Frontends that use a |
|
47 | # regardless of what frontend it is attached to. Frontends that use a | |
48 | # kernel in-process can define additional aliases that will only work in |
|
48 | # kernel in-process can define additional aliases that will only work in | |
49 | # their case. For example, things like 'less' or 'clear' that manipulate |
|
49 | # their case. For example, things like 'less' or 'clear' that manipulate | |
50 | # the terminal should NOT be declared here, as they will only work if the |
|
50 | # the terminal should NOT be declared here, as they will only work if the | |
51 | # kernel is running inside a true terminal, and not over the network. |
|
51 | # kernel is running inside a true terminal, and not over the network. | |
52 |
|
52 | |||
53 | if os.name == 'posix': |
|
53 | if os.name == 'posix': | |
54 | default_aliases = [('mkdir', 'mkdir'), ('rmdir', 'rmdir'), |
|
54 | default_aliases = [('mkdir', 'mkdir'), ('rmdir', 'rmdir'), | |
55 | ('mv', 'mv -i'), ('rm', 'rm -i'), ('cp', 'cp -i'), |
|
55 | ('mv', 'mv -i'), ('rm', 'rm -i'), ('cp', 'cp -i'), | |
56 | ('cat', 'cat'), |
|
56 | ('cat', 'cat'), | |
57 | ] |
|
57 | ] | |
58 | # Useful set of ls aliases. The GNU and BSD options are a little |
|
58 | # Useful set of ls aliases. The GNU and BSD options are a little | |
59 | # different, so we make aliases that provide as similar as possible |
|
59 | # different, so we make aliases that provide as similar as possible | |
60 | # behavior in ipython, by passing the right flags for each platform |
|
60 | # behavior in ipython, by passing the right flags for each platform | |
61 | if sys.platform.startswith('linux'): |
|
61 | if sys.platform.startswith('linux'): | |
62 | ls_aliases = [('ls', 'ls -F --color'), |
|
62 | ls_aliases = [('ls', 'ls -F --color'), | |
63 | # long ls |
|
63 | # long ls | |
64 | ('ll', 'ls -F -o --color'), |
|
64 | ('ll', 'ls -F -o --color'), | |
65 | # ls normal files only |
|
65 | # ls normal files only | |
66 | ('lf', 'ls -F -o --color %l | grep ^-'), |
|
66 | ('lf', 'ls -F -o --color %l | grep ^-'), | |
67 | # ls symbolic links |
|
67 | # ls symbolic links | |
68 | ('lk', 'ls -F -o --color %l | grep ^l'), |
|
68 | ('lk', 'ls -F -o --color %l | grep ^l'), | |
69 | # directories or links to directories, |
|
69 | # directories or links to directories, | |
70 | ('ldir', 'ls -F -o --color %l | grep /$'), |
|
70 | ('ldir', 'ls -F -o --color %l | grep /$'), | |
71 | # things which are executable |
|
71 | # things which are executable | |
72 | ('lx', 'ls -F -o --color %l | grep ^-..x'), |
|
72 | ('lx', 'ls -F -o --color %l | grep ^-..x'), | |
73 | ] |
|
73 | ] | |
74 | else: |
|
74 | else: | |
75 | # BSD, OSX, etc. |
|
75 | # BSD, OSX, etc. | |
76 | ls_aliases = [('ls', 'ls -F'), |
|
76 | ls_aliases = [('ls', 'ls -F'), | |
77 | # long ls |
|
77 | # long ls | |
78 | ('ll', 'ls -F -l'), |
|
78 | ('ll', 'ls -F -l'), | |
79 | # ls normal files only |
|
79 | # ls normal files only | |
80 | ('lf', 'ls -F -l %l | grep ^-'), |
|
80 | ('lf', 'ls -F -l %l | grep ^-'), | |
81 | # ls symbolic links |
|
81 | # ls symbolic links | |
82 | ('lk', 'ls -F -l %l | grep ^l'), |
|
82 | ('lk', 'ls -F -l %l | grep ^l'), | |
83 | # directories or links to directories, |
|
83 | # directories or links to directories, | |
84 | ('ldir', 'ls -F -l %l | grep /$'), |
|
84 | ('ldir', 'ls -F -l %l | grep /$'), | |
85 | # things which are executable |
|
85 | # things which are executable | |
86 | ('lx', 'ls -F -l %l | grep ^-..x'), |
|
86 | ('lx', 'ls -F -l %l | grep ^-..x'), | |
87 | ] |
|
87 | ] | |
88 | default_aliases = default_aliases + ls_aliases |
|
88 | default_aliases = default_aliases + ls_aliases | |
89 | elif os.name in ['nt', 'dos']: |
|
89 | elif os.name in ['nt', 'dos']: | |
90 | default_aliases = [('ls', 'dir /on'), |
|
90 | default_aliases = [('ls', 'dir /on'), | |
91 | ('ddir', 'dir /ad /on'), ('ldir', 'dir /ad /on'), |
|
91 | ('ddir', 'dir /ad /on'), ('ldir', 'dir /ad /on'), | |
92 | ('mkdir', 'mkdir'), ('rmdir', 'rmdir'), |
|
92 | ('mkdir', 'mkdir'), ('rmdir', 'rmdir'), | |
93 | ('echo', 'echo'), ('ren', 'ren'), ('copy', 'copy'), |
|
93 | ('echo', 'echo'), ('ren', 'ren'), ('copy', 'copy'), | |
94 | ] |
|
94 | ] | |
95 | else: |
|
95 | else: | |
96 | default_aliases = [] |
|
96 | default_aliases = [] | |
97 |
|
97 | |||
98 | return default_aliases |
|
98 | return default_aliases | |
99 |
|
99 | |||
100 |
|
100 | |||
101 | class AliasError(Exception): |
|
101 | class AliasError(Exception): | |
102 | pass |
|
102 | pass | |
103 |
|
103 | |||
104 |
|
104 | |||
105 | class InvalidAliasError(AliasError): |
|
105 | class InvalidAliasError(AliasError): | |
106 | pass |
|
106 | pass | |
107 |
|
107 | |||
108 | #----------------------------------------------------------------------------- |
|
108 | #----------------------------------------------------------------------------- | |
109 | # Main AliasManager class |
|
109 | # Main AliasManager class | |
110 | #----------------------------------------------------------------------------- |
|
110 | #----------------------------------------------------------------------------- | |
111 |
|
111 | |||
112 | class AliasManager(Configurable): |
|
112 | class AliasManager(Configurable): | |
113 |
|
113 | |||
114 | default_aliases = List(default_aliases(), config=True) |
|
114 | default_aliases = List(default_aliases(), config=True) | |
115 | user_aliases = List(default_value=[], config=True) |
|
115 | user_aliases = List(default_value=[], config=True) | |
116 | shell = Instance('IPython.core.interactiveshell.InteractiveShellABC') |
|
116 | shell = Instance('IPython.core.interactiveshell.InteractiveShellABC') | |
117 |
|
117 | |||
118 | def __init__(self, shell=None, config=None): |
|
118 | def __init__(self, shell=None, config=None): | |
119 | super(AliasManager, self).__init__(shell=shell, config=config) |
|
119 | super(AliasManager, self).__init__(shell=shell, config=config) | |
120 | self.alias_table = {} |
|
120 | self.alias_table = {} | |
121 | self.exclude_aliases() |
|
121 | self.exclude_aliases() | |
122 | self.init_aliases() |
|
122 | self.init_aliases() | |
123 |
|
123 | |||
124 | def __contains__(self, name): |
|
124 | def __contains__(self, name): | |
125 | return name in self.alias_table |
|
125 | return name in self.alias_table | |
126 |
|
126 | |||
127 | @property |
|
127 | @property | |
128 | def aliases(self): |
|
128 | def aliases(self): | |
129 | return [(item[0], item[1][1]) for item in self.alias_table.iteritems()] |
|
129 | return [(item[0], item[1][1]) for item in self.alias_table.iteritems()] | |
130 |
|
130 | |||
131 | def exclude_aliases(self): |
|
131 | def exclude_aliases(self): | |
132 | # set of things NOT to alias (keywords, builtins and some magics) |
|
132 | # set of things NOT to alias (keywords, builtins and some magics) | |
133 | no_alias = set(['cd','popd','pushd','dhist','alias','unalias']) |
|
133 | no_alias = set(['cd','popd','pushd','dhist','alias','unalias']) | |
134 | no_alias.update(set(keyword.kwlist)) |
|
134 | no_alias.update(set(keyword.kwlist)) | |
135 | no_alias.update(set(__builtin__.__dict__.keys())) |
|
135 | no_alias.update(set(__builtin__.__dict__.keys())) | |
136 | self.no_alias = no_alias |
|
136 | self.no_alias = no_alias | |
137 |
|
137 | |||
138 | def init_aliases(self): |
|
138 | def init_aliases(self): | |
139 | # Load default aliases |
|
139 | # Load default aliases | |
140 | for name, cmd in self.default_aliases: |
|
140 | for name, cmd in self.default_aliases: | |
141 | self.soft_define_alias(name, cmd) |
|
141 | self.soft_define_alias(name, cmd) | |
142 |
|
142 | |||
143 | # Load user aliases |
|
143 | # Load user aliases | |
144 | for name, cmd in self.user_aliases: |
|
144 | for name, cmd in self.user_aliases: | |
145 | self.soft_define_alias(name, cmd) |
|
145 | self.soft_define_alias(name, cmd) | |
146 |
|
146 | |||
147 | def clear_aliases(self): |
|
147 | def clear_aliases(self): | |
148 | self.alias_table.clear() |
|
148 | self.alias_table.clear() | |
149 |
|
149 | |||
150 | def soft_define_alias(self, name, cmd): |
|
150 | def soft_define_alias(self, name, cmd): | |
151 | """Define an alias, but don't raise on an AliasError.""" |
|
151 | """Define an alias, but don't raise on an AliasError.""" | |
152 | try: |
|
152 | try: | |
153 | self.define_alias(name, cmd) |
|
153 | self.define_alias(name, cmd) | |
154 | except AliasError, e: |
|
154 | except AliasError, e: | |
155 | error("Invalid alias: %s" % e) |
|
155 | error("Invalid alias: %s" % e) | |
156 |
|
156 | |||
157 | def define_alias(self, name, cmd): |
|
157 | def define_alias(self, name, cmd): | |
158 | """Define a new alias after validating it. |
|
158 | """Define a new alias after validating it. | |
159 |
|
159 | |||
160 | This will raise an :exc:`AliasError` if there are validation |
|
160 | This will raise an :exc:`AliasError` if there are validation | |
161 | problems. |
|
161 | problems. | |
162 | """ |
|
162 | """ | |
163 | nargs = self.validate_alias(name, cmd) |
|
163 | nargs = self.validate_alias(name, cmd) | |
164 | self.alias_table[name] = (nargs, cmd) |
|
164 | self.alias_table[name] = (nargs, cmd) | |
165 |
|
165 | |||
166 | def undefine_alias(self, name): |
|
166 | def undefine_alias(self, name): | |
167 | if self.alias_table.has_key(name): |
|
167 | if self.alias_table.has_key(name): | |
168 | del self.alias_table[name] |
|
168 | del self.alias_table[name] | |
169 |
|
169 | |||
170 | def validate_alias(self, name, cmd): |
|
170 | def validate_alias(self, name, cmd): | |
171 | """Validate an alias and return the its number of arguments.""" |
|
171 | """Validate an alias and return the its number of arguments.""" | |
172 | if name in self.no_alias: |
|
172 | if name in self.no_alias: | |
173 | raise InvalidAliasError("The name %s can't be aliased " |
|
173 | raise InvalidAliasError("The name %s can't be aliased " | |
174 | "because it is a keyword or builtin." % name) |
|
174 | "because it is a keyword or builtin." % name) | |
175 | if not (isinstance(cmd, basestring)): |
|
175 | if not (isinstance(cmd, basestring)): | |
176 | raise InvalidAliasError("An alias command must be a string, " |
|
176 | raise InvalidAliasError("An alias command must be a string, " | |
177 | "got: %r" % name) |
|
177 | "got: %r" % name) | |
178 | nargs = cmd.count('%s') |
|
178 | nargs = cmd.count('%s') | |
179 | if nargs>0 and cmd.find('%l')>=0: |
|
179 | if nargs>0 and cmd.find('%l')>=0: | |
180 | raise InvalidAliasError('The %s and %l specifiers are mutually ' |
|
180 | raise InvalidAliasError('The %s and %l specifiers are mutually ' | |
181 | 'exclusive in alias definitions.') |
|
181 | 'exclusive in alias definitions.') | |
182 | return nargs |
|
182 | return nargs | |
183 |
|
183 | |||
184 | def call_alias(self, alias, rest=''): |
|
184 | def call_alias(self, alias, rest=''): | |
185 | """Call an alias given its name and the rest of the line.""" |
|
185 | """Call an alias given its name and the rest of the line.""" | |
186 | cmd = self.transform_alias(alias, rest) |
|
186 | cmd = self.transform_alias(alias, rest) | |
187 | try: |
|
187 | try: | |
188 | self.shell.system(cmd) |
|
188 | self.shell.system(cmd) | |
189 | except: |
|
189 | except: | |
190 | self.shell.showtraceback() |
|
190 | self.shell.showtraceback() | |
191 |
|
191 | |||
192 | def transform_alias(self, alias,rest=''): |
|
192 | def transform_alias(self, alias,rest=''): | |
193 | """Transform alias to system command string.""" |
|
193 | """Transform alias to system command string.""" | |
194 | nargs, cmd = self.alias_table[alias] |
|
194 | nargs, cmd = self.alias_table[alias] | |
195 |
|
195 | |||
196 | if ' ' in cmd and os.path.isfile(cmd): |
|
196 | if ' ' in cmd and os.path.isfile(cmd): | |
197 | cmd = '"%s"' % cmd |
|
197 | cmd = '"%s"' % cmd | |
198 |
|
198 | |||
199 | # Expand the %l special to be the user's input line |
|
199 | # Expand the %l special to be the user's input line | |
200 | if cmd.find('%l') >= 0: |
|
200 | if cmd.find('%l') >= 0: | |
201 | cmd = cmd.replace('%l', rest) |
|
201 | cmd = cmd.replace('%l', rest) | |
202 | rest = '' |
|
202 | rest = '' | |
203 | if nargs==0: |
|
203 | if nargs==0: | |
204 | # Simple, argument-less aliases |
|
204 | # Simple, argument-less aliases | |
205 | cmd = '%s %s' % (cmd, rest) |
|
205 | cmd = '%s %s' % (cmd, rest) | |
206 | else: |
|
206 | else: | |
207 | # Handle aliases with positional arguments |
|
207 | # Handle aliases with positional arguments | |
208 | args = rest.split(None, nargs) |
|
208 | args = rest.split(None, nargs) | |
209 | if len(args) < nargs: |
|
209 | if len(args) < nargs: | |
210 | raise AliasError('Alias <%s> requires %s arguments, %s given.' % |
|
210 | raise AliasError('Alias <%s> requires %s arguments, %s given.' % | |
211 | (alias, nargs, len(args))) |
|
211 | (alias, nargs, len(args))) | |
212 | cmd = '%s %s' % (cmd % tuple(args[:nargs]),' '.join(args[nargs:])) |
|
212 | cmd = '%s %s' % (cmd % tuple(args[:nargs]),' '.join(args[nargs:])) | |
213 | return cmd |
|
213 | return cmd | |
214 |
|
214 | |||
215 | def expand_alias(self, line): |
|
215 | def expand_alias(self, line): | |
216 | """ Expand an alias in the command line |
|
216 | """ Expand an alias in the command line | |
217 |
|
217 | |||
218 | Returns the provided command line, possibly with the first word |
|
218 | Returns the provided command line, possibly with the first word | |
219 | (command) translated according to alias expansion rules. |
|
219 | (command) translated according to alias expansion rules. | |
220 |
|
220 | |||
221 | [ipython]|16> _ip.expand_aliases("np myfile.txt") |
|
221 | [ipython]|16> _ip.expand_aliases("np myfile.txt") | |
222 | <16> 'q:/opt/np/notepad++.exe myfile.txt' |
|
222 | <16> 'q:/opt/np/notepad++.exe myfile.txt' | |
223 | """ |
|
223 | """ | |
224 |
|
224 | |||
225 | pre,fn,rest = split_user_input(line) |
|
225 | pre,_,fn,rest = split_user_input(line) | |
226 | res = pre + self.expand_aliases(fn, rest) |
|
226 | res = pre + self.expand_aliases(fn, rest) | |
227 | return res |
|
227 | return res | |
228 |
|
228 | |||
229 | def expand_aliases(self, fn, rest): |
|
229 | def expand_aliases(self, fn, rest): | |
230 | """Expand multiple levels of aliases: |
|
230 | """Expand multiple levels of aliases: | |
231 |
|
231 | |||
232 | if: |
|
232 | if: | |
233 |
|
233 | |||
234 | alias foo bar /tmp |
|
234 | alias foo bar /tmp | |
235 | alias baz foo |
|
235 | alias baz foo | |
236 |
|
236 | |||
237 | then: |
|
237 | then: | |
238 |
|
238 | |||
239 | baz huhhahhei -> bar /tmp huhhahhei |
|
239 | baz huhhahhei -> bar /tmp huhhahhei | |
240 | """ |
|
240 | """ | |
241 | line = fn + " " + rest |
|
241 | line = fn + " " + rest | |
242 |
|
242 | |||
243 | done = set() |
|
243 | done = set() | |
244 | while 1: |
|
244 | while 1: | |
245 | pre,fn,rest = split_user_input(line, shell_line_split) |
|
245 | pre,_,fn,rest = split_user_input(line, shell_line_split) | |
246 | if fn in self.alias_table: |
|
246 | if fn in self.alias_table: | |
247 | if fn in done: |
|
247 | if fn in done: | |
248 | warn("Cyclic alias definition, repeated '%s'" % fn) |
|
248 | warn("Cyclic alias definition, repeated '%s'" % fn) | |
249 | return "" |
|
249 | return "" | |
250 | done.add(fn) |
|
250 | done.add(fn) | |
251 |
|
251 | |||
252 | l2 = self.transform_alias(fn, rest) |
|
252 | l2 = self.transform_alias(fn, rest) | |
253 | if l2 == line: |
|
253 | if l2 == line: | |
254 | break |
|
254 | break | |
255 | # ls -> ls -F should not recurse forever |
|
255 | # ls -> ls -F should not recurse forever | |
256 | if l2.split(None,1)[0] == line.split(None,1)[0]: |
|
256 | if l2.split(None,1)[0] == line.split(None,1)[0]: | |
257 | line = l2 |
|
257 | line = l2 | |
258 | break |
|
258 | break | |
259 | line=l2 |
|
259 | line=l2 | |
260 | else: |
|
260 | else: | |
261 | break |
|
261 | break | |
262 |
|
262 | |||
263 | return line |
|
263 | return line |
@@ -1,769 +1,773 | |||||
1 | # -*- coding: utf-8 -*- |
|
1 | # -*- coding: utf-8 -*- | |
2 | """Tools for inspecting Python objects. |
|
2 | """Tools for inspecting Python objects. | |
3 |
|
3 | |||
4 | Uses syntax highlighting for presenting the various information elements. |
|
4 | Uses syntax highlighting for presenting the various information elements. | |
5 |
|
5 | |||
6 | Similar in spirit to the inspect module, but all calls take a name argument to |
|
6 | Similar in spirit to the inspect module, but all calls take a name argument to | |
7 | reference the name under which an object is being read. |
|
7 | reference the name under which an object is being read. | |
8 | """ |
|
8 | """ | |
9 |
|
9 | |||
10 | #***************************************************************************** |
|
10 | #***************************************************************************** | |
11 | # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu> |
|
11 | # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu> | |
12 | # |
|
12 | # | |
13 | # Distributed under the terms of the BSD License. The full license is in |
|
13 | # Distributed under the terms of the BSD License. The full license is in | |
14 | # the file COPYING, distributed as part of this software. |
|
14 | # the file COPYING, distributed as part of this software. | |
15 | #***************************************************************************** |
|
15 | #***************************************************************************** | |
16 |
|
16 | |||
17 | __all__ = ['Inspector','InspectColors'] |
|
17 | __all__ = ['Inspector','InspectColors'] | |
18 |
|
18 | |||
19 | # stdlib modules |
|
19 | # stdlib modules | |
20 | import __builtin__ |
|
20 | import __builtin__ | |
21 | import inspect |
|
21 | import inspect | |
22 | import linecache |
|
22 | import linecache | |
23 | import os |
|
23 | import os | |
24 | import sys |
|
24 | import sys | |
25 | import types |
|
25 | import types | |
26 | from collections import namedtuple |
|
26 | from collections import namedtuple | |
|
27 | try: | |||
27 | from itertools import izip_longest |
|
28 | from itertools import izip_longest | |
|
29 | except ImportError: | |||
|
30 | from itertools import zip_longest as izip_longest | |||
28 |
|
31 | |||
29 | # IPython's own |
|
32 | # IPython's own | |
30 | from IPython.core import page |
|
33 | from IPython.core import page | |
31 | from IPython.utils import PyColorize |
|
34 | from IPython.utils import PyColorize | |
32 | from IPython.utils import io |
|
35 | from IPython.utils import io | |
|
36 | from IPython.utils import py3compat | |||
33 | from IPython.utils.text import indent |
|
37 | from IPython.utils.text import indent | |
34 | from IPython.utils.wildcard import list_namespace |
|
38 | from IPython.utils.wildcard import list_namespace | |
35 | from IPython.utils.coloransi import * |
|
39 | from IPython.utils.coloransi import * | |
36 |
|
40 | |||
37 | #**************************************************************************** |
|
41 | #**************************************************************************** | |
38 | # Builtin color schemes |
|
42 | # Builtin color schemes | |
39 |
|
43 | |||
40 | Colors = TermColors # just a shorthand |
|
44 | Colors = TermColors # just a shorthand | |
41 |
|
45 | |||
42 | # Build a few color schemes |
|
46 | # Build a few color schemes | |
43 | NoColor = ColorScheme( |
|
47 | NoColor = ColorScheme( | |
44 | 'NoColor',{ |
|
48 | 'NoColor',{ | |
45 | 'header' : Colors.NoColor, |
|
49 | 'header' : Colors.NoColor, | |
46 | 'normal' : Colors.NoColor # color off (usu. Colors.Normal) |
|
50 | 'normal' : Colors.NoColor # color off (usu. Colors.Normal) | |
47 | } ) |
|
51 | } ) | |
48 |
|
52 | |||
49 | LinuxColors = ColorScheme( |
|
53 | LinuxColors = ColorScheme( | |
50 | 'Linux',{ |
|
54 | 'Linux',{ | |
51 | 'header' : Colors.LightRed, |
|
55 | 'header' : Colors.LightRed, | |
52 | 'normal' : Colors.Normal # color off (usu. Colors.Normal) |
|
56 | 'normal' : Colors.Normal # color off (usu. Colors.Normal) | |
53 | } ) |
|
57 | } ) | |
54 |
|
58 | |||
55 | LightBGColors = ColorScheme( |
|
59 | LightBGColors = ColorScheme( | |
56 | 'LightBG',{ |
|
60 | 'LightBG',{ | |
57 | 'header' : Colors.Red, |
|
61 | 'header' : Colors.Red, | |
58 | 'normal' : Colors.Normal # color off (usu. Colors.Normal) |
|
62 | 'normal' : Colors.Normal # color off (usu. Colors.Normal) | |
59 | } ) |
|
63 | } ) | |
60 |
|
64 | |||
61 | # Build table of color schemes (needed by the parser) |
|
65 | # Build table of color schemes (needed by the parser) | |
62 | InspectColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors], |
|
66 | InspectColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors], | |
63 | 'Linux') |
|
67 | 'Linux') | |
64 |
|
68 | |||
65 | #**************************************************************************** |
|
69 | #**************************************************************************** | |
66 | # Auxiliary functions and objects |
|
70 | # Auxiliary functions and objects | |
67 |
|
71 | |||
68 | # See the messaging spec for the definition of all these fields. This list |
|
72 | # See the messaging spec for the definition of all these fields. This list | |
69 | # effectively defines the order of display |
|
73 | # effectively defines the order of display | |
70 | info_fields = ['type_name', 'base_class', 'string_form', 'namespace', |
|
74 | info_fields = ['type_name', 'base_class', 'string_form', 'namespace', | |
71 | 'length', 'file', 'definition', 'docstring', 'source', |
|
75 | 'length', 'file', 'definition', 'docstring', 'source', | |
72 | 'init_definition', 'class_docstring', 'init_docstring', |
|
76 | 'init_definition', 'class_docstring', 'init_docstring', | |
73 | 'call_def', 'call_docstring', |
|
77 | 'call_def', 'call_docstring', | |
74 | # These won't be printed but will be used to determine how to |
|
78 | # These won't be printed but will be used to determine how to | |
75 | # format the object |
|
79 | # format the object | |
76 | 'ismagic', 'isalias', 'isclass', 'argspec', 'found', 'name' |
|
80 | 'ismagic', 'isalias', 'isclass', 'argspec', 'found', 'name' | |
77 | ] |
|
81 | ] | |
78 |
|
82 | |||
79 |
|
83 | |||
80 | def object_info(**kw): |
|
84 | def object_info(**kw): | |
81 | """Make an object info dict with all fields present.""" |
|
85 | """Make an object info dict with all fields present.""" | |
82 | infodict = dict(izip_longest(info_fields, [None])) |
|
86 | infodict = dict(izip_longest(info_fields, [None])) | |
83 | infodict.update(kw) |
|
87 | infodict.update(kw) | |
84 | return infodict |
|
88 | return infodict | |
85 |
|
89 | |||
86 |
|
90 | |||
87 | def getdoc(obj): |
|
91 | def getdoc(obj): | |
88 | """Stable wrapper around inspect.getdoc. |
|
92 | """Stable wrapper around inspect.getdoc. | |
89 |
|
93 | |||
90 | This can't crash because of attribute problems. |
|
94 | This can't crash because of attribute problems. | |
91 |
|
95 | |||
92 | It also attempts to call a getdoc() method on the given object. This |
|
96 | It also attempts to call a getdoc() method on the given object. This | |
93 | allows objects which provide their docstrings via non-standard mechanisms |
|
97 | allows objects which provide their docstrings via non-standard mechanisms | |
94 | (like Pyro proxies) to still be inspected by ipython's ? system.""" |
|
98 | (like Pyro proxies) to still be inspected by ipython's ? system.""" | |
95 |
|
99 | |||
96 | ds = None # default return value |
|
100 | ds = None # default return value | |
97 | try: |
|
101 | try: | |
98 | ds = inspect.getdoc(obj) |
|
102 | ds = inspect.getdoc(obj) | |
99 | except: |
|
103 | except: | |
100 | # Harden against an inspect failure, which can occur with |
|
104 | # Harden against an inspect failure, which can occur with | |
101 | # SWIG-wrapped extensions. |
|
105 | # SWIG-wrapped extensions. | |
102 | pass |
|
106 | pass | |
103 | # Allow objects to offer customized documentation via a getdoc method: |
|
107 | # Allow objects to offer customized documentation via a getdoc method: | |
104 | try: |
|
108 | try: | |
105 | ds2 = obj.getdoc() |
|
109 | ds2 = obj.getdoc() | |
106 | except: |
|
110 | except: | |
107 | pass |
|
111 | pass | |
108 | else: |
|
112 | else: | |
109 | # if we get extra info, we add it to the normal docstring. |
|
113 | # if we get extra info, we add it to the normal docstring. | |
110 | if ds is None: |
|
114 | if ds is None: | |
111 | ds = ds2 |
|
115 | ds = ds2 | |
112 | else: |
|
116 | else: | |
113 | ds = '%s\n%s' % (ds,ds2) |
|
117 | ds = '%s\n%s' % (ds,ds2) | |
114 | return ds |
|
118 | return ds | |
115 |
|
119 | |||
116 |
|
120 | |||
117 | def getsource(obj,is_binary=False): |
|
121 | def getsource(obj,is_binary=False): | |
118 | """Wrapper around inspect.getsource. |
|
122 | """Wrapper around inspect.getsource. | |
119 |
|
123 | |||
120 | This can be modified by other projects to provide customized source |
|
124 | This can be modified by other projects to provide customized source | |
121 | extraction. |
|
125 | extraction. | |
122 |
|
126 | |||
123 | Inputs: |
|
127 | Inputs: | |
124 |
|
128 | |||
125 | - obj: an object whose source code we will attempt to extract. |
|
129 | - obj: an object whose source code we will attempt to extract. | |
126 |
|
130 | |||
127 | Optional inputs: |
|
131 | Optional inputs: | |
128 |
|
132 | |||
129 | - is_binary: whether the object is known to come from a binary source. |
|
133 | - is_binary: whether the object is known to come from a binary source. | |
130 | This implementation will skip returning any output for binary objects, but |
|
134 | This implementation will skip returning any output for binary objects, but | |
131 | custom extractors may know how to meaningfully process them.""" |
|
135 | custom extractors may know how to meaningfully process them.""" | |
132 |
|
136 | |||
133 | if is_binary: |
|
137 | if is_binary: | |
134 | return None |
|
138 | return None | |
135 | else: |
|
139 | else: | |
136 | # get source if obj was decorated with @decorator |
|
140 | # get source if obj was decorated with @decorator | |
137 | if hasattr(obj,"__wrapped__"): |
|
141 | if hasattr(obj,"__wrapped__"): | |
138 | obj = obj.__wrapped__ |
|
142 | obj = obj.__wrapped__ | |
139 | try: |
|
143 | try: | |
140 | src = inspect.getsource(obj) |
|
144 | src = inspect.getsource(obj) | |
141 | except TypeError: |
|
145 | except TypeError: | |
142 | if hasattr(obj,'__class__'): |
|
146 | if hasattr(obj,'__class__'): | |
143 | src = inspect.getsource(obj.__class__) |
|
147 | src = inspect.getsource(obj.__class__) | |
144 | return src |
|
148 | return src | |
145 |
|
149 | |||
146 | def getargspec(obj): |
|
150 | def getargspec(obj): | |
147 | """Get the names and default values of a function's arguments. |
|
151 | """Get the names and default values of a function's arguments. | |
148 |
|
152 | |||
149 | A tuple of four things is returned: (args, varargs, varkw, defaults). |
|
153 | A tuple of four things is returned: (args, varargs, varkw, defaults). | |
150 | 'args' is a list of the argument names (it may contain nested lists). |
|
154 | 'args' is a list of the argument names (it may contain nested lists). | |
151 | 'varargs' and 'varkw' are the names of the * and ** arguments or None. |
|
155 | 'varargs' and 'varkw' are the names of the * and ** arguments or None. | |
152 | 'defaults' is an n-tuple of the default values of the last n arguments. |
|
156 | 'defaults' is an n-tuple of the default values of the last n arguments. | |
153 |
|
157 | |||
154 | Modified version of inspect.getargspec from the Python Standard |
|
158 | Modified version of inspect.getargspec from the Python Standard | |
155 | Library.""" |
|
159 | Library.""" | |
156 |
|
160 | |||
157 | if inspect.isfunction(obj): |
|
161 | if inspect.isfunction(obj): | |
158 | func_obj = obj |
|
162 | func_obj = obj | |
159 | elif inspect.ismethod(obj): |
|
163 | elif inspect.ismethod(obj): | |
160 | func_obj = obj.im_func |
|
164 | func_obj = obj.im_func | |
161 | elif hasattr(obj, '__call__'): |
|
165 | elif hasattr(obj, '__call__'): | |
162 | func_obj = obj.__call__ |
|
166 | func_obj = obj.__call__ | |
163 | else: |
|
167 | else: | |
164 | raise TypeError('arg is not a Python function') |
|
168 | raise TypeError('arg is not a Python function') | |
165 | args, varargs, varkw = inspect.getargs(func_obj.func_code) |
|
169 | args, varargs, varkw = inspect.getargs(func_obj.func_code) | |
166 | return args, varargs, varkw, func_obj.func_defaults |
|
170 | return args, varargs, varkw, func_obj.func_defaults | |
167 |
|
171 | |||
168 |
|
172 | |||
169 | def format_argspec(argspec): |
|
173 | def format_argspec(argspec): | |
170 | """Format argspect, convenience wrapper around inspect's. |
|
174 | """Format argspect, convenience wrapper around inspect's. | |
171 |
|
175 | |||
172 | This takes a dict instead of ordered arguments and calls |
|
176 | This takes a dict instead of ordered arguments and calls | |
173 | inspect.format_argspec with the arguments in the necessary order. |
|
177 | inspect.format_argspec with the arguments in the necessary order. | |
174 | """ |
|
178 | """ | |
175 | return inspect.formatargspec(argspec['args'], argspec['varargs'], |
|
179 | return inspect.formatargspec(argspec['args'], argspec['varargs'], | |
176 | argspec['varkw'], argspec['defaults']) |
|
180 | argspec['varkw'], argspec['defaults']) | |
177 |
|
181 | |||
178 |
|
182 | |||
179 | def call_tip(oinfo, format_call=True): |
|
183 | def call_tip(oinfo, format_call=True): | |
180 | """Extract call tip data from an oinfo dict. |
|
184 | """Extract call tip data from an oinfo dict. | |
181 |
|
185 | |||
182 | Parameters |
|
186 | Parameters | |
183 | ---------- |
|
187 | ---------- | |
184 | oinfo : dict |
|
188 | oinfo : dict | |
185 |
|
189 | |||
186 | format_call : bool, optional |
|
190 | format_call : bool, optional | |
187 | If True, the call line is formatted and returned as a string. If not, a |
|
191 | If True, the call line is formatted and returned as a string. If not, a | |
188 | tuple of (name, argspec) is returned. |
|
192 | tuple of (name, argspec) is returned. | |
189 |
|
193 | |||
190 | Returns |
|
194 | Returns | |
191 | ------- |
|
195 | ------- | |
192 | call_info : None, str or (str, dict) tuple. |
|
196 | call_info : None, str or (str, dict) tuple. | |
193 | When format_call is True, the whole call information is formattted as a |
|
197 | When format_call is True, the whole call information is formattted as a | |
194 | single string. Otherwise, the object's name and its argspec dict are |
|
198 | single string. Otherwise, the object's name and its argspec dict are | |
195 | returned. If no call information is available, None is returned. |
|
199 | returned. If no call information is available, None is returned. | |
196 |
|
200 | |||
197 | docstring : str or None |
|
201 | docstring : str or None | |
198 | The most relevant docstring for calling purposes is returned, if |
|
202 | The most relevant docstring for calling purposes is returned, if | |
199 | available. The priority is: call docstring for callable instances, then |
|
203 | available. The priority is: call docstring for callable instances, then | |
200 | constructor docstring for classes, then main object's docstring otherwise |
|
204 | constructor docstring for classes, then main object's docstring otherwise | |
201 | (regular functions). |
|
205 | (regular functions). | |
202 | """ |
|
206 | """ | |
203 | # Get call definition |
|
207 | # Get call definition | |
204 | argspec = oinfo.get('argspec') |
|
208 | argspec = oinfo.get('argspec') | |
205 | if argspec is None: |
|
209 | if argspec is None: | |
206 | call_line = None |
|
210 | call_line = None | |
207 | else: |
|
211 | else: | |
208 | # Callable objects will have 'self' as their first argument, prune |
|
212 | # Callable objects will have 'self' as their first argument, prune | |
209 | # it out if it's there for clarity (since users do *not* pass an |
|
213 | # it out if it's there for clarity (since users do *not* pass an | |
210 | # extra first argument explicitly). |
|
214 | # extra first argument explicitly). | |
211 | try: |
|
215 | try: | |
212 | has_self = argspec['args'][0] == 'self' |
|
216 | has_self = argspec['args'][0] == 'self' | |
213 | except (KeyError, IndexError): |
|
217 | except (KeyError, IndexError): | |
214 | pass |
|
218 | pass | |
215 | else: |
|
219 | else: | |
216 | if has_self: |
|
220 | if has_self: | |
217 | argspec['args'] = argspec['args'][1:] |
|
221 | argspec['args'] = argspec['args'][1:] | |
218 |
|
222 | |||
219 | call_line = oinfo['name']+format_argspec(argspec) |
|
223 | call_line = oinfo['name']+format_argspec(argspec) | |
220 |
|
224 | |||
221 | # Now get docstring. |
|
225 | # Now get docstring. | |
222 | # The priority is: call docstring, constructor docstring, main one. |
|
226 | # The priority is: call docstring, constructor docstring, main one. | |
223 | doc = oinfo.get('call_docstring') |
|
227 | doc = oinfo.get('call_docstring') | |
224 | if doc is None: |
|
228 | if doc is None: | |
225 | doc = oinfo.get('init_docstring') |
|
229 | doc = oinfo.get('init_docstring') | |
226 | if doc is None: |
|
230 | if doc is None: | |
227 | doc = oinfo.get('docstring','') |
|
231 | doc = oinfo.get('docstring','') | |
228 |
|
232 | |||
229 | return call_line, doc |
|
233 | return call_line, doc | |
230 |
|
234 | |||
231 |
|
235 | |||
232 | class Inspector: |
|
236 | class Inspector: | |
233 | def __init__(self, color_table=InspectColors, |
|
237 | def __init__(self, color_table=InspectColors, | |
234 | code_color_table=PyColorize.ANSICodeColors, |
|
238 | code_color_table=PyColorize.ANSICodeColors, | |
235 | scheme='NoColor', |
|
239 | scheme='NoColor', | |
236 | str_detail_level=0): |
|
240 | str_detail_level=0): | |
237 | self.color_table = color_table |
|
241 | self.color_table = color_table | |
238 | self.parser = PyColorize.Parser(code_color_table,out='str') |
|
242 | self.parser = PyColorize.Parser(code_color_table,out='str') | |
239 | self.format = self.parser.format |
|
243 | self.format = self.parser.format | |
240 | self.str_detail_level = str_detail_level |
|
244 | self.str_detail_level = str_detail_level | |
241 | self.set_active_scheme(scheme) |
|
245 | self.set_active_scheme(scheme) | |
242 |
|
246 | |||
243 | def _getdef(self,obj,oname=''): |
|
247 | def _getdef(self,obj,oname=''): | |
244 | """Return the definition header for any callable object. |
|
248 | """Return the definition header for any callable object. | |
245 |
|
249 | |||
246 | If any exception is generated, None is returned instead and the |
|
250 | If any exception is generated, None is returned instead and the | |
247 | exception is suppressed.""" |
|
251 | exception is suppressed.""" | |
248 |
|
252 | |||
249 | try: |
|
253 | try: | |
250 | # We need a plain string here, NOT unicode! |
|
254 | # We need a plain string here, NOT unicode! | |
251 | hdef = oname + inspect.formatargspec(*getargspec(obj)) |
|
255 | hdef = oname + inspect.formatargspec(*getargspec(obj)) | |
252 | return hdef.encode('ascii') |
|
256 | return py3compat.unicode_to_str(hdef.encode('ascii')) | |
253 | except: |
|
257 | except: | |
254 | return None |
|
258 | return None | |
255 |
|
259 | |||
256 | def __head(self,h): |
|
260 | def __head(self,h): | |
257 | """Return a header string with proper colors.""" |
|
261 | """Return a header string with proper colors.""" | |
258 | return '%s%s%s' % (self.color_table.active_colors.header,h, |
|
262 | return '%s%s%s' % (self.color_table.active_colors.header,h, | |
259 | self.color_table.active_colors.normal) |
|
263 | self.color_table.active_colors.normal) | |
260 |
|
264 | |||
261 | def set_active_scheme(self,scheme): |
|
265 | def set_active_scheme(self,scheme): | |
262 | self.color_table.set_active_scheme(scheme) |
|
266 | self.color_table.set_active_scheme(scheme) | |
263 | self.parser.color_table.set_active_scheme(scheme) |
|
267 | self.parser.color_table.set_active_scheme(scheme) | |
264 |
|
268 | |||
265 | def noinfo(self,msg,oname): |
|
269 | def noinfo(self,msg,oname): | |
266 | """Generic message when no information is found.""" |
|
270 | """Generic message when no information is found.""" | |
267 | print 'No %s found' % msg, |
|
271 | print 'No %s found' % msg, | |
268 | if oname: |
|
272 | if oname: | |
269 | print 'for %s' % oname |
|
273 | print 'for %s' % oname | |
270 | else: |
|
274 | else: | |
271 |
|
275 | |||
272 |
|
276 | |||
273 | def pdef(self,obj,oname=''): |
|
277 | def pdef(self,obj,oname=''): | |
274 | """Print the definition header for any callable object. |
|
278 | """Print the definition header for any callable object. | |
275 |
|
279 | |||
276 | If the object is a class, print the constructor information.""" |
|
280 | If the object is a class, print the constructor information.""" | |
277 |
|
281 | |||
278 | if not callable(obj): |
|
282 | if not callable(obj): | |
279 | print 'Object is not callable.' |
|
283 | print 'Object is not callable.' | |
280 | return |
|
284 | return | |
281 |
|
285 | |||
282 | header = '' |
|
286 | header = '' | |
283 |
|
287 | |||
284 | if inspect.isclass(obj): |
|
288 | if inspect.isclass(obj): | |
285 | header = self.__head('Class constructor information:\n') |
|
289 | header = self.__head('Class constructor information:\n') | |
286 | obj = obj.__init__ |
|
290 | obj = obj.__init__ | |
287 | elif type(obj) is types.InstanceType: |
|
291 | elif type(obj) is types.InstanceType: | |
288 | obj = obj.__call__ |
|
292 | obj = obj.__call__ | |
289 |
|
293 | |||
290 | output = self._getdef(obj,oname) |
|
294 | output = self._getdef(obj,oname) | |
291 | if output is None: |
|
295 | if output is None: | |
292 | self.noinfo('definition header',oname) |
|
296 | self.noinfo('definition header',oname) | |
293 | else: |
|
297 | else: | |
294 | print >>io.stdout, header,self.format(output), |
|
298 | print >>io.stdout, header,self.format(output), | |
295 |
|
299 | |||
296 | def pdoc(self,obj,oname='',formatter = None): |
|
300 | def pdoc(self,obj,oname='',formatter = None): | |
297 | """Print the docstring for any object. |
|
301 | """Print the docstring for any object. | |
298 |
|
302 | |||
299 | Optional: |
|
303 | Optional: | |
300 | -formatter: a function to run the docstring through for specially |
|
304 | -formatter: a function to run the docstring through for specially | |
301 | formatted docstrings. |
|
305 | formatted docstrings. | |
302 |
|
306 | |||
303 | Examples |
|
307 | Examples | |
304 | -------- |
|
308 | -------- | |
305 |
|
309 | |||
306 | In [1]: class NoInit: |
|
310 | In [1]: class NoInit: | |
307 | ...: pass |
|
311 | ...: pass | |
308 |
|
312 | |||
309 | In [2]: class NoDoc: |
|
313 | In [2]: class NoDoc: | |
310 | ...: def __init__(self): |
|
314 | ...: def __init__(self): | |
311 | ...: pass |
|
315 | ...: pass | |
312 |
|
316 | |||
313 | In [3]: %pdoc NoDoc |
|
317 | In [3]: %pdoc NoDoc | |
314 | No documentation found for NoDoc |
|
318 | No documentation found for NoDoc | |
315 |
|
319 | |||
316 | In [4]: %pdoc NoInit |
|
320 | In [4]: %pdoc NoInit | |
317 | No documentation found for NoInit |
|
321 | No documentation found for NoInit | |
318 |
|
322 | |||
319 | In [5]: obj = NoInit() |
|
323 | In [5]: obj = NoInit() | |
320 |
|
324 | |||
321 | In [6]: %pdoc obj |
|
325 | In [6]: %pdoc obj | |
322 | No documentation found for obj |
|
326 | No documentation found for obj | |
323 |
|
327 | |||
324 | In [5]: obj2 = NoDoc() |
|
328 | In [5]: obj2 = NoDoc() | |
325 |
|
329 | |||
326 | In [6]: %pdoc obj2 |
|
330 | In [6]: %pdoc obj2 | |
327 | No documentation found for obj2 |
|
331 | No documentation found for obj2 | |
328 | """ |
|
332 | """ | |
329 |
|
333 | |||
330 | head = self.__head # For convenience |
|
334 | head = self.__head # For convenience | |
331 | lines = [] |
|
335 | lines = [] | |
332 | ds = getdoc(obj) |
|
336 | ds = getdoc(obj) | |
333 | if formatter: |
|
337 | if formatter: | |
334 | ds = formatter(ds) |
|
338 | ds = formatter(ds) | |
335 | if ds: |
|
339 | if ds: | |
336 | lines.append(head("Class Docstring:")) |
|
340 | lines.append(head("Class Docstring:")) | |
337 | lines.append(indent(ds)) |
|
341 | lines.append(indent(ds)) | |
338 | if inspect.isclass(obj) and hasattr(obj, '__init__'): |
|
342 | if inspect.isclass(obj) and hasattr(obj, '__init__'): | |
339 | init_ds = getdoc(obj.__init__) |
|
343 | init_ds = getdoc(obj.__init__) | |
340 | if init_ds is not None: |
|
344 | if init_ds is not None: | |
341 | lines.append(head("Constructor Docstring:")) |
|
345 | lines.append(head("Constructor Docstring:")) | |
342 | lines.append(indent(init_ds)) |
|
346 | lines.append(indent(init_ds)) | |
343 | elif (type(obj) is types.InstanceType or isinstance(obj,object)) \ |
|
347 | elif (type(obj) is types.InstanceType or isinstance(obj,object)) \ | |
344 | and hasattr(obj,'__call__'): |
|
348 | and hasattr(obj,'__call__'): | |
345 | call_ds = getdoc(obj.__call__) |
|
349 | call_ds = getdoc(obj.__call__) | |
346 | if call_ds: |
|
350 | if call_ds: | |
347 | lines.append(head("Calling Docstring:")) |
|
351 | lines.append(head("Calling Docstring:")) | |
348 | lines.append(indent(call_ds)) |
|
352 | lines.append(indent(call_ds)) | |
349 |
|
353 | |||
350 | if not lines: |
|
354 | if not lines: | |
351 | self.noinfo('documentation',oname) |
|
355 | self.noinfo('documentation',oname) | |
352 | else: |
|
356 | else: | |
353 | page.page('\n'.join(lines)) |
|
357 | page.page('\n'.join(lines)) | |
354 |
|
358 | |||
355 | def psource(self,obj,oname=''): |
|
359 | def psource(self,obj,oname=''): | |
356 | """Print the source code for an object.""" |
|
360 | """Print the source code for an object.""" | |
357 |
|
361 | |||
358 | # Flush the source cache because inspect can return out-of-date source |
|
362 | # Flush the source cache because inspect can return out-of-date source | |
359 | linecache.checkcache() |
|
363 | linecache.checkcache() | |
360 | try: |
|
364 | try: | |
361 | src = getsource(obj) |
|
365 | src = getsource(obj) | |
362 | except: |
|
366 | except: | |
363 | self.noinfo('source',oname) |
|
367 | self.noinfo('source',oname) | |
364 | else: |
|
368 | else: | |
365 | page.page(self.format(src)) |
|
369 | page.page(self.format(py3compat.unicode_to_str(src))) | |
366 |
|
370 | |||
367 | def pfile(self,obj,oname=''): |
|
371 | def pfile(self,obj,oname=''): | |
368 | """Show the whole file where an object was defined.""" |
|
372 | """Show the whole file where an object was defined.""" | |
369 |
|
373 | |||
370 | try: |
|
374 | try: | |
371 | try: |
|
375 | try: | |
372 | lineno = inspect.getsourcelines(obj)[1] |
|
376 | lineno = inspect.getsourcelines(obj)[1] | |
373 | except TypeError: |
|
377 | except TypeError: | |
374 | # For instances, try the class object like getsource() does |
|
378 | # For instances, try the class object like getsource() does | |
375 | if hasattr(obj,'__class__'): |
|
379 | if hasattr(obj,'__class__'): | |
376 | lineno = inspect.getsourcelines(obj.__class__)[1] |
|
380 | lineno = inspect.getsourcelines(obj.__class__)[1] | |
377 | # Adjust the inspected object so getabsfile() below works |
|
381 | # Adjust the inspected object so getabsfile() below works | |
378 | obj = obj.__class__ |
|
382 | obj = obj.__class__ | |
379 | except: |
|
383 | except: | |
380 | self.noinfo('file',oname) |
|
384 | self.noinfo('file',oname) | |
381 | return |
|
385 | return | |
382 |
|
386 | |||
383 | # We only reach this point if object was successfully queried |
|
387 | # We only reach this point if object was successfully queried | |
384 |
|
388 | |||
385 | # run contents of file through pager starting at line |
|
389 | # run contents of file through pager starting at line | |
386 | # where the object is defined |
|
390 | # where the object is defined | |
387 | ofile = inspect.getabsfile(obj) |
|
391 | ofile = inspect.getabsfile(obj) | |
388 |
|
392 | |||
389 | if ofile.endswith(('.so', '.dll', '.pyd')): |
|
393 | if ofile.endswith(('.so', '.dll', '.pyd')): | |
390 | print 'File %r is binary, not printing.' % ofile |
|
394 | print 'File %r is binary, not printing.' % ofile | |
391 | elif not os.path.isfile(ofile): |
|
395 | elif not os.path.isfile(ofile): | |
392 | print 'File %r does not exist, not printing.' % ofile |
|
396 | print 'File %r does not exist, not printing.' % ofile | |
393 | else: |
|
397 | else: | |
394 | # Print only text files, not extension binaries. Note that |
|
398 | # Print only text files, not extension binaries. Note that | |
395 | # getsourcelines returns lineno with 1-offset and page() uses |
|
399 | # getsourcelines returns lineno with 1-offset and page() uses | |
396 | # 0-offset, so we must adjust. |
|
400 | # 0-offset, so we must adjust. | |
397 | page.page(self.format(open(ofile).read()),lineno-1) |
|
401 | page.page(self.format(open(ofile).read()),lineno-1) | |
398 |
|
402 | |||
399 | def _format_fields(self, fields, title_width=12): |
|
403 | def _format_fields(self, fields, title_width=12): | |
400 | """Formats a list of fields for display. |
|
404 | """Formats a list of fields for display. | |
401 |
|
405 | |||
402 | Parameters |
|
406 | Parameters | |
403 | ---------- |
|
407 | ---------- | |
404 | fields : list |
|
408 | fields : list | |
405 | A list of 2-tuples: (field_title, field_content) |
|
409 | A list of 2-tuples: (field_title, field_content) | |
406 | title_width : int |
|
410 | title_width : int | |
407 | How many characters to pad titles to. Default 12. |
|
411 | How many characters to pad titles to. Default 12. | |
408 | """ |
|
412 | """ | |
409 | out = [] |
|
413 | out = [] | |
410 | header = self.__head |
|
414 | header = self.__head | |
411 | for title, content in fields: |
|
415 | for title, content in fields: | |
412 | if len(content.splitlines()) > 1: |
|
416 | if len(content.splitlines()) > 1: | |
413 | title = header(title + ":") + "\n" |
|
417 | title = header(title + ":") + "\n" | |
414 | else: |
|
418 | else: | |
415 | title = header((title+":").ljust(title_width)) |
|
419 | title = header((title+":").ljust(title_width)) | |
416 | out.append(title + content) |
|
420 | out.append(title + content) | |
417 | return "\n".join(out) |
|
421 | return "\n".join(out) | |
418 |
|
422 | |||
419 | # The fields to be displayed by pinfo: (fancy_name, key_in_info_dict) |
|
423 | # The fields to be displayed by pinfo: (fancy_name, key_in_info_dict) | |
420 | pinfo_fields1 = [("Type", "type_name"), |
|
424 | pinfo_fields1 = [("Type", "type_name"), | |
421 | ("Base Class", "base_class"), |
|
425 | ("Base Class", "base_class"), | |
422 | ("String Form", "string_form"), |
|
426 | ("String Form", "string_form"), | |
423 | ("Namespace", "namespace"), |
|
427 | ("Namespace", "namespace"), | |
424 | ("Length", "length"), |
|
428 | ("Length", "length"), | |
425 | ("File", "file"), |
|
429 | ("File", "file"), | |
426 | ("Definition", "definition")] |
|
430 | ("Definition", "definition")] | |
427 |
|
431 | |||
428 | pinfo_fields_obj = [("Class Docstring", "class_docstring"), |
|
432 | pinfo_fields_obj = [("Class Docstring", "class_docstring"), | |
429 | ("Constructor Docstring","init_docstring"), |
|
433 | ("Constructor Docstring","init_docstring"), | |
430 | ("Call def", "call_def"), |
|
434 | ("Call def", "call_def"), | |
431 | ("Call docstring", "call_docstring")] |
|
435 | ("Call docstring", "call_docstring")] | |
432 |
|
436 | |||
433 | def pinfo(self,obj,oname='',formatter=None,info=None,detail_level=0): |
|
437 | def pinfo(self,obj,oname='',formatter=None,info=None,detail_level=0): | |
434 | """Show detailed information about an object. |
|
438 | """Show detailed information about an object. | |
435 |
|
439 | |||
436 | Optional arguments: |
|
440 | Optional arguments: | |
437 |
|
441 | |||
438 | - oname: name of the variable pointing to the object. |
|
442 | - oname: name of the variable pointing to the object. | |
439 |
|
443 | |||
440 | - formatter: special formatter for docstrings (see pdoc) |
|
444 | - formatter: special formatter for docstrings (see pdoc) | |
441 |
|
445 | |||
442 | - info: a structure with some information fields which may have been |
|
446 | - info: a structure with some information fields which may have been | |
443 | precomputed already. |
|
447 | precomputed already. | |
444 |
|
448 | |||
445 | - detail_level: if set to 1, more information is given. |
|
449 | - detail_level: if set to 1, more information is given. | |
446 | """ |
|
450 | """ | |
447 | info = self.info(obj, oname=oname, formatter=formatter, |
|
451 | info = self.info(obj, oname=oname, formatter=formatter, | |
448 | info=info, detail_level=detail_level) |
|
452 | info=info, detail_level=detail_level) | |
449 | displayfields = [] |
|
453 | displayfields = [] | |
450 | for title, key in self.pinfo_fields1: |
|
454 | for title, key in self.pinfo_fields1: | |
451 | field = info[key] |
|
455 | field = info[key] | |
452 | if field is not None: |
|
456 | if field is not None: | |
453 | displayfields.append((title, field.rstrip())) |
|
457 | displayfields.append((title, field.rstrip())) | |
454 |
|
458 | |||
455 | # Source or docstring, depending on detail level and whether |
|
459 | # Source or docstring, depending on detail level and whether | |
456 | # source found. |
|
460 | # source found. | |
457 | if detail_level > 0 and info['source'] is not None: |
|
461 | if detail_level > 0 and info['source'] is not None: | |
458 | displayfields.append(("Source", info['source'])) |
|
462 | displayfields.append(("Source", info['source'])) | |
459 | elif info['docstring'] is not None: |
|
463 | elif info['docstring'] is not None: | |
460 | displayfields.append(("Docstring", info["docstring"])) |
|
464 | displayfields.append(("Docstring", info["docstring"])) | |
461 |
|
465 | |||
462 | # Constructor info for classes |
|
466 | # Constructor info for classes | |
463 | if info['isclass']: |
|
467 | if info['isclass']: | |
464 | if info['init_definition'] or info['init_docstring']: |
|
468 | if info['init_definition'] or info['init_docstring']: | |
465 | displayfields.append(("Constructor information", "")) |
|
469 | displayfields.append(("Constructor information", "")) | |
466 | if info['init_definition'] is not None: |
|
470 | if info['init_definition'] is not None: | |
467 | displayfields.append((" Definition", |
|
471 | displayfields.append((" Definition", | |
468 | info['init_definition'].rstrip())) |
|
472 | info['init_definition'].rstrip())) | |
469 | if info['init_docstring'] is not None: |
|
473 | if info['init_docstring'] is not None: | |
470 | displayfields.append((" Docstring", |
|
474 | displayfields.append((" Docstring", | |
471 | indent(info['init_docstring']))) |
|
475 | indent(info['init_docstring']))) | |
472 |
|
476 | |||
473 | # Info for objects: |
|
477 | # Info for objects: | |
474 | else: |
|
478 | else: | |
475 | for title, key in self.pinfo_fields_obj: |
|
479 | for title, key in self.pinfo_fields_obj: | |
476 | field = info[key] |
|
480 | field = info[key] | |
477 | if field is not None: |
|
481 | if field is not None: | |
478 | displayfields.append((title, field.rstrip())) |
|
482 | displayfields.append((title, field.rstrip())) | |
479 |
|
483 | |||
480 | # Finally send to printer/pager: |
|
484 | # Finally send to printer/pager: | |
481 | if displayfields: |
|
485 | if displayfields: | |
482 | page.page(self._format_fields(displayfields)) |
|
486 | page.page(self._format_fields(displayfields)) | |
483 |
|
487 | |||
484 | def info(self, obj, oname='', formatter=None, info=None, detail_level=0): |
|
488 | def info(self, obj, oname='', formatter=None, info=None, detail_level=0): | |
485 | """Compute a dict with detailed information about an object. |
|
489 | """Compute a dict with detailed information about an object. | |
486 |
|
490 | |||
487 | Optional arguments: |
|
491 | Optional arguments: | |
488 |
|
492 | |||
489 | - oname: name of the variable pointing to the object. |
|
493 | - oname: name of the variable pointing to the object. | |
490 |
|
494 | |||
491 | - formatter: special formatter for docstrings (see pdoc) |
|
495 | - formatter: special formatter for docstrings (see pdoc) | |
492 |
|
496 | |||
493 | - info: a structure with some information fields which may have been |
|
497 | - info: a structure with some information fields which may have been | |
494 | precomputed already. |
|
498 | precomputed already. | |
495 |
|
499 | |||
496 | - detail_level: if set to 1, more information is given. |
|
500 | - detail_level: if set to 1, more information is given. | |
497 | """ |
|
501 | """ | |
498 |
|
502 | |||
499 | obj_type = type(obj) |
|
503 | obj_type = type(obj) | |
500 |
|
504 | |||
501 | header = self.__head |
|
505 | header = self.__head | |
502 | if info is None: |
|
506 | if info is None: | |
503 | ismagic = 0 |
|
507 | ismagic = 0 | |
504 | isalias = 0 |
|
508 | isalias = 0 | |
505 | ospace = '' |
|
509 | ospace = '' | |
506 | else: |
|
510 | else: | |
507 | ismagic = info.ismagic |
|
511 | ismagic = info.ismagic | |
508 | isalias = info.isalias |
|
512 | isalias = info.isalias | |
509 | ospace = info.namespace |
|
513 | ospace = info.namespace | |
510 |
|
514 | |||
511 | # Get docstring, special-casing aliases: |
|
515 | # Get docstring, special-casing aliases: | |
512 | if isalias: |
|
516 | if isalias: | |
513 | if not callable(obj): |
|
517 | if not callable(obj): | |
514 | try: |
|
518 | try: | |
515 | ds = "Alias to the system command:\n %s" % obj[1] |
|
519 | ds = "Alias to the system command:\n %s" % obj[1] | |
516 | except: |
|
520 | except: | |
517 | ds = "Alias: " + str(obj) |
|
521 | ds = "Alias: " + str(obj) | |
518 | else: |
|
522 | else: | |
519 | ds = "Alias to " + str(obj) |
|
523 | ds = "Alias to " + str(obj) | |
520 | if obj.__doc__: |
|
524 | if obj.__doc__: | |
521 | ds += "\nDocstring:\n" + obj.__doc__ |
|
525 | ds += "\nDocstring:\n" + obj.__doc__ | |
522 | else: |
|
526 | else: | |
523 | ds = getdoc(obj) |
|
527 | ds = getdoc(obj) | |
524 | if ds is None: |
|
528 | if ds is None: | |
525 | ds = '<no docstring>' |
|
529 | ds = '<no docstring>' | |
526 | if formatter is not None: |
|
530 | if formatter is not None: | |
527 | ds = formatter(ds) |
|
531 | ds = formatter(ds) | |
528 |
|
532 | |||
529 | # store output in a dict, we initialize it here and fill it as we go |
|
533 | # store output in a dict, we initialize it here and fill it as we go | |
530 | out = dict(name=oname, found=True, isalias=isalias, ismagic=ismagic) |
|
534 | out = dict(name=oname, found=True, isalias=isalias, ismagic=ismagic) | |
531 |
|
535 | |||
532 | string_max = 200 # max size of strings to show (snipped if longer) |
|
536 | string_max = 200 # max size of strings to show (snipped if longer) | |
533 | shalf = int((string_max -5)/2) |
|
537 | shalf = int((string_max -5)/2) | |
534 |
|
538 | |||
535 | if ismagic: |
|
539 | if ismagic: | |
536 | obj_type_name = 'Magic function' |
|
540 | obj_type_name = 'Magic function' | |
537 | elif isalias: |
|
541 | elif isalias: | |
538 | obj_type_name = 'System alias' |
|
542 | obj_type_name = 'System alias' | |
539 | else: |
|
543 | else: | |
540 | obj_type_name = obj_type.__name__ |
|
544 | obj_type_name = obj_type.__name__ | |
541 | out['type_name'] = obj_type_name |
|
545 | out['type_name'] = obj_type_name | |
542 |
|
546 | |||
543 | try: |
|
547 | try: | |
544 | bclass = obj.__class__ |
|
548 | bclass = obj.__class__ | |
545 | out['base_class'] = str(bclass) |
|
549 | out['base_class'] = str(bclass) | |
546 | except: pass |
|
550 | except: pass | |
547 |
|
551 | |||
548 | # String form, but snip if too long in ? form (full in ??) |
|
552 | # String form, but snip if too long in ? form (full in ??) | |
549 | if detail_level >= self.str_detail_level: |
|
553 | if detail_level >= self.str_detail_level: | |
550 | try: |
|
554 | try: | |
551 | ostr = str(obj) |
|
555 | ostr = str(obj) | |
552 | str_head = 'string_form' |
|
556 | str_head = 'string_form' | |
553 | if not detail_level and len(ostr)>string_max: |
|
557 | if not detail_level and len(ostr)>string_max: | |
554 | ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:] |
|
558 | ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:] | |
555 | ostr = ("\n" + " " * len(str_head.expandtabs())).\ |
|
559 | ostr = ("\n" + " " * len(str_head.expandtabs())).\ | |
556 | join(q.strip() for q in ostr.split("\n")) |
|
560 | join(q.strip() for q in ostr.split("\n")) | |
557 | out[str_head] = ostr |
|
561 | out[str_head] = ostr | |
558 | except: |
|
562 | except: | |
559 | pass |
|
563 | pass | |
560 |
|
564 | |||
561 | if ospace: |
|
565 | if ospace: | |
562 | out['namespace'] = ospace |
|
566 | out['namespace'] = ospace | |
563 |
|
567 | |||
564 | # Length (for strings and lists) |
|
568 | # Length (for strings and lists) | |
565 | try: |
|
569 | try: | |
566 | out['length'] = str(len(obj)) |
|
570 | out['length'] = str(len(obj)) | |
567 | except: pass |
|
571 | except: pass | |
568 |
|
572 | |||
569 | # Filename where object was defined |
|
573 | # Filename where object was defined | |
570 | binary_file = False |
|
574 | binary_file = False | |
571 | try: |
|
575 | try: | |
572 | try: |
|
576 | try: | |
573 | fname = inspect.getabsfile(obj) |
|
577 | fname = inspect.getabsfile(obj) | |
574 | except TypeError: |
|
578 | except TypeError: | |
575 | # For an instance, the file that matters is where its class was |
|
579 | # For an instance, the file that matters is where its class was | |
576 | # declared. |
|
580 | # declared. | |
577 | if hasattr(obj,'__class__'): |
|
581 | if hasattr(obj,'__class__'): | |
578 | fname = inspect.getabsfile(obj.__class__) |
|
582 | fname = inspect.getabsfile(obj.__class__) | |
579 | if fname.endswith('<string>'): |
|
583 | if fname.endswith('<string>'): | |
580 | fname = 'Dynamically generated function. No source code available.' |
|
584 | fname = 'Dynamically generated function. No source code available.' | |
581 | if fname.endswith(('.so', '.dll', '.pyd')): |
|
585 | if fname.endswith(('.so', '.dll', '.pyd')): | |
582 | binary_file = True |
|
586 | binary_file = True | |
583 | out['file'] = fname |
|
587 | out['file'] = fname | |
584 | except: |
|
588 | except: | |
585 | # if anything goes wrong, we don't want to show source, so it's as |
|
589 | # if anything goes wrong, we don't want to show source, so it's as | |
586 | # if the file was binary |
|
590 | # if the file was binary | |
587 | binary_file = True |
|
591 | binary_file = True | |
588 |
|
592 | |||
589 | # reconstruct the function definition and print it: |
|
593 | # reconstruct the function definition and print it: | |
590 | defln = self._getdef(obj, oname) |
|
594 | defln = self._getdef(obj, oname) | |
591 | if defln: |
|
595 | if defln: | |
592 | out['definition'] = self.format(defln) |
|
596 | out['definition'] = self.format(defln) | |
593 |
|
597 | |||
594 | # Docstrings only in detail 0 mode, since source contains them (we |
|
598 | # Docstrings only in detail 0 mode, since source contains them (we | |
595 | # avoid repetitions). If source fails, we add them back, see below. |
|
599 | # avoid repetitions). If source fails, we add them back, see below. | |
596 | if ds and detail_level == 0: |
|
600 | if ds and detail_level == 0: | |
597 | out['docstring'] = ds |
|
601 | out['docstring'] = ds | |
598 |
|
602 | |||
599 | # Original source code for any callable |
|
603 | # Original source code for any callable | |
600 | if detail_level: |
|
604 | if detail_level: | |
601 | # Flush the source cache because inspect can return out-of-date |
|
605 | # Flush the source cache because inspect can return out-of-date | |
602 | # source |
|
606 | # source | |
603 | linecache.checkcache() |
|
607 | linecache.checkcache() | |
604 | source = None |
|
608 | source = None | |
605 | try: |
|
609 | try: | |
606 | try: |
|
610 | try: | |
607 | src = getsource(obj,binary_file) |
|
611 | src = getsource(obj,binary_file) | |
608 | except TypeError: |
|
612 | except TypeError: | |
609 | if hasattr(obj,'__class__'): |
|
613 | if hasattr(obj,'__class__'): | |
610 | src = getsource(obj.__class__,binary_file) |
|
614 | src = getsource(obj.__class__,binary_file) | |
611 | if src is not None: |
|
615 | if src is not None: | |
612 | source = self.format(src) |
|
616 | source = self.format(src) | |
613 | out['source'] = source.rstrip() |
|
617 | out['source'] = source.rstrip() | |
614 | except Exception: |
|
618 | except Exception: | |
615 | pass |
|
619 | pass | |
616 |
|
620 | |||
617 | if ds and source is None: |
|
621 | if ds and source is None: | |
618 | out['docstring'] = ds |
|
622 | out['docstring'] = ds | |
619 |
|
623 | |||
620 |
|
624 | |||
621 | # Constructor docstring for classes |
|
625 | # Constructor docstring for classes | |
622 | if inspect.isclass(obj): |
|
626 | if inspect.isclass(obj): | |
623 | out['isclass'] = True |
|
627 | out['isclass'] = True | |
624 | # reconstruct the function definition and print it: |
|
628 | # reconstruct the function definition and print it: | |
625 | try: |
|
629 | try: | |
626 | obj_init = obj.__init__ |
|
630 | obj_init = obj.__init__ | |
627 | except AttributeError: |
|
631 | except AttributeError: | |
628 | init_def = init_ds = None |
|
632 | init_def = init_ds = None | |
629 | else: |
|
633 | else: | |
630 | init_def = self._getdef(obj_init,oname) |
|
634 | init_def = self._getdef(obj_init,oname) | |
631 | init_ds = getdoc(obj_init) |
|
635 | init_ds = getdoc(obj_init) | |
632 | # Skip Python's auto-generated docstrings |
|
636 | # Skip Python's auto-generated docstrings | |
633 | if init_ds and \ |
|
637 | if init_ds and \ | |
634 | init_ds.startswith('x.__init__(...) initializes'): |
|
638 | init_ds.startswith('x.__init__(...) initializes'): | |
635 | init_ds = None |
|
639 | init_ds = None | |
636 |
|
640 | |||
637 | if init_def or init_ds: |
|
641 | if init_def or init_ds: | |
638 | if init_def: |
|
642 | if init_def: | |
639 | out['init_definition'] = self.format(init_def) |
|
643 | out['init_definition'] = self.format(init_def) | |
640 | if init_ds: |
|
644 | if init_ds: | |
641 | out['init_docstring'] = init_ds |
|
645 | out['init_docstring'] = init_ds | |
642 |
|
646 | |||
643 | # and class docstring for instances: |
|
647 | # and class docstring for instances: | |
644 | else: |
|
648 | else: | |
645 | # First, check whether the instance docstring is identical to the |
|
649 | # First, check whether the instance docstring is identical to the | |
646 | # class one, and print it separately if they don't coincide. In |
|
650 | # class one, and print it separately if they don't coincide. In | |
647 | # most cases they will, but it's nice to print all the info for |
|
651 | # most cases they will, but it's nice to print all the info for | |
648 | # objects which use instance-customized docstrings. |
|
652 | # objects which use instance-customized docstrings. | |
649 | if ds: |
|
653 | if ds: | |
650 | try: |
|
654 | try: | |
651 | cls = getattr(obj,'__class__') |
|
655 | cls = getattr(obj,'__class__') | |
652 | except: |
|
656 | except: | |
653 | class_ds = None |
|
657 | class_ds = None | |
654 | else: |
|
658 | else: | |
655 | class_ds = getdoc(cls) |
|
659 | class_ds = getdoc(cls) | |
656 | # Skip Python's auto-generated docstrings |
|
660 | # Skip Python's auto-generated docstrings | |
657 | if class_ds and \ |
|
661 | if class_ds and \ | |
658 | (class_ds.startswith('function(code, globals[,') or \ |
|
662 | (class_ds.startswith('function(code, globals[,') or \ | |
659 | class_ds.startswith('instancemethod(function, instance,') or \ |
|
663 | class_ds.startswith('instancemethod(function, instance,') or \ | |
660 | class_ds.startswith('module(name[,') ): |
|
664 | class_ds.startswith('module(name[,') ): | |
661 | class_ds = None |
|
665 | class_ds = None | |
662 | if class_ds and ds != class_ds: |
|
666 | if class_ds and ds != class_ds: | |
663 | out['class_docstring'] = class_ds |
|
667 | out['class_docstring'] = class_ds | |
664 |
|
668 | |||
665 | # Next, try to show constructor docstrings |
|
669 | # Next, try to show constructor docstrings | |
666 | try: |
|
670 | try: | |
667 | init_ds = getdoc(obj.__init__) |
|
671 | init_ds = getdoc(obj.__init__) | |
668 | # Skip Python's auto-generated docstrings |
|
672 | # Skip Python's auto-generated docstrings | |
669 | if init_ds and \ |
|
673 | if init_ds and \ | |
670 | init_ds.startswith('x.__init__(...) initializes'): |
|
674 | init_ds.startswith('x.__init__(...) initializes'): | |
671 | init_ds = None |
|
675 | init_ds = None | |
672 | except AttributeError: |
|
676 | except AttributeError: | |
673 | init_ds = None |
|
677 | init_ds = None | |
674 | if init_ds: |
|
678 | if init_ds: | |
675 | out['init_docstring'] = init_ds |
|
679 | out['init_docstring'] = init_ds | |
676 |
|
680 | |||
677 | # Call form docstring for callable instances |
|
681 | # Call form docstring for callable instances | |
678 | if hasattr(obj, '__call__'): |
|
682 | if hasattr(obj, '__call__'): | |
679 | call_def = self._getdef(obj.__call__, oname) |
|
683 | call_def = self._getdef(obj.__call__, oname) | |
680 | if call_def is not None: |
|
684 | if call_def is not None: | |
681 | out['call_def'] = self.format(call_def) |
|
685 | out['call_def'] = self.format(call_def) | |
682 | call_ds = getdoc(obj.__call__) |
|
686 | call_ds = getdoc(obj.__call__) | |
683 | # Skip Python's auto-generated docstrings |
|
687 | # Skip Python's auto-generated docstrings | |
684 | if call_ds and call_ds.startswith('x.__call__(...) <==> x(...)'): |
|
688 | if call_ds and call_ds.startswith('x.__call__(...) <==> x(...)'): | |
685 | call_ds = None |
|
689 | call_ds = None | |
686 | if call_ds: |
|
690 | if call_ds: | |
687 | out['call_docstring'] = call_ds |
|
691 | out['call_docstring'] = call_ds | |
688 |
|
692 | |||
689 | # Compute the object's argspec as a callable. The key is to decide |
|
693 | # Compute the object's argspec as a callable. The key is to decide | |
690 | # whether to pull it from the object itself, from its __init__ or |
|
694 | # whether to pull it from the object itself, from its __init__ or | |
691 | # from its __call__ method. |
|
695 | # from its __call__ method. | |
692 |
|
696 | |||
693 | if inspect.isclass(obj): |
|
697 | if inspect.isclass(obj): | |
694 | # Old-style classes need not have an __init__ |
|
698 | # Old-style classes need not have an __init__ | |
695 | callable_obj = getattr(obj, "__init__", None) |
|
699 | callable_obj = getattr(obj, "__init__", None) | |
696 | elif callable(obj): |
|
700 | elif callable(obj): | |
697 | callable_obj = obj |
|
701 | callable_obj = obj | |
698 | else: |
|
702 | else: | |
699 | callable_obj = None |
|
703 | callable_obj = None | |
700 |
|
704 | |||
701 | if callable_obj: |
|
705 | if callable_obj: | |
702 | try: |
|
706 | try: | |
703 | args, varargs, varkw, defaults = getargspec(callable_obj) |
|
707 | args, varargs, varkw, defaults = getargspec(callable_obj) | |
704 | except (TypeError, AttributeError): |
|
708 | except (TypeError, AttributeError): | |
705 | # For extensions/builtins we can't retrieve the argspec |
|
709 | # For extensions/builtins we can't retrieve the argspec | |
706 | pass |
|
710 | pass | |
707 | else: |
|
711 | else: | |
708 | out['argspec'] = dict(args=args, varargs=varargs, |
|
712 | out['argspec'] = dict(args=args, varargs=varargs, | |
709 | varkw=varkw, defaults=defaults) |
|
713 | varkw=varkw, defaults=defaults) | |
710 |
|
714 | |||
711 | return object_info(**out) |
|
715 | return object_info(**out) | |
712 |
|
716 | |||
713 |
|
717 | |||
714 | def psearch(self,pattern,ns_table,ns_search=[], |
|
718 | def psearch(self,pattern,ns_table,ns_search=[], | |
715 | ignore_case=False,show_all=False): |
|
719 | ignore_case=False,show_all=False): | |
716 | """Search namespaces with wildcards for objects. |
|
720 | """Search namespaces with wildcards for objects. | |
717 |
|
721 | |||
718 | Arguments: |
|
722 | Arguments: | |
719 |
|
723 | |||
720 | - pattern: string containing shell-like wildcards to use in namespace |
|
724 | - pattern: string containing shell-like wildcards to use in namespace | |
721 | searches and optionally a type specification to narrow the search to |
|
725 | searches and optionally a type specification to narrow the search to | |
722 | objects of that type. |
|
726 | objects of that type. | |
723 |
|
727 | |||
724 | - ns_table: dict of name->namespaces for search. |
|
728 | - ns_table: dict of name->namespaces for search. | |
725 |
|
729 | |||
726 | Optional arguments: |
|
730 | Optional arguments: | |
727 |
|
731 | |||
728 | - ns_search: list of namespace names to include in search. |
|
732 | - ns_search: list of namespace names to include in search. | |
729 |
|
733 | |||
730 | - ignore_case(False): make the search case-insensitive. |
|
734 | - ignore_case(False): make the search case-insensitive. | |
731 |
|
735 | |||
732 | - show_all(False): show all names, including those starting with |
|
736 | - show_all(False): show all names, including those starting with | |
733 | underscores. |
|
737 | underscores. | |
734 | """ |
|
738 | """ | |
735 | #print 'ps pattern:<%r>' % pattern # dbg |
|
739 | #print 'ps pattern:<%r>' % pattern # dbg | |
736 |
|
740 | |||
737 | # defaults |
|
741 | # defaults | |
738 | type_pattern = 'all' |
|
742 | type_pattern = 'all' | |
739 | filter = '' |
|
743 | filter = '' | |
740 |
|
744 | |||
741 | cmds = pattern.split() |
|
745 | cmds = pattern.split() | |
742 | len_cmds = len(cmds) |
|
746 | len_cmds = len(cmds) | |
743 | if len_cmds == 1: |
|
747 | if len_cmds == 1: | |
744 | # Only filter pattern given |
|
748 | # Only filter pattern given | |
745 | filter = cmds[0] |
|
749 | filter = cmds[0] | |
746 | elif len_cmds == 2: |
|
750 | elif len_cmds == 2: | |
747 | # Both filter and type specified |
|
751 | # Both filter and type specified | |
748 | filter,type_pattern = cmds |
|
752 | filter,type_pattern = cmds | |
749 | else: |
|
753 | else: | |
750 | raise ValueError('invalid argument string for psearch: <%s>' % |
|
754 | raise ValueError('invalid argument string for psearch: <%s>' % | |
751 | pattern) |
|
755 | pattern) | |
752 |
|
756 | |||
753 | # filter search namespaces |
|
757 | # filter search namespaces | |
754 | for name in ns_search: |
|
758 | for name in ns_search: | |
755 | if name not in ns_table: |
|
759 | if name not in ns_table: | |
756 | raise ValueError('invalid namespace <%s>. Valid names: %s' % |
|
760 | raise ValueError('invalid namespace <%s>. Valid names: %s' % | |
757 | (name,ns_table.keys())) |
|
761 | (name,ns_table.keys())) | |
758 |
|
762 | |||
759 | #print 'type_pattern:',type_pattern # dbg |
|
763 | #print 'type_pattern:',type_pattern # dbg | |
760 | search_result = [] |
|
764 | search_result = [] | |
761 | for ns_name in ns_search: |
|
765 | for ns_name in ns_search: | |
762 | ns = ns_table[ns_name] |
|
766 | ns = ns_table[ns_name] | |
763 | tmp_res = list(list_namespace(ns,type_pattern,filter, |
|
767 | tmp_res = list(list_namespace(ns,type_pattern,filter, | |
764 | ignore_case=ignore_case, |
|
768 | ignore_case=ignore_case, | |
765 | show_all=show_all)) |
|
769 | show_all=show_all)) | |
766 | search_result.extend(tmp_res) |
|
770 | search_result.extend(tmp_res) | |
767 | search_result.sort() |
|
771 | search_result.sort() | |
768 |
|
772 | |||
769 | page.page('\n'.join(search_result)) |
|
773 | page.page('\n'.join(search_result)) |
@@ -1,1012 +1,1015 | |||||
1 | # encoding: utf-8 |
|
1 | # encoding: utf-8 | |
2 | """ |
|
2 | """ | |
3 | Prefiltering components. |
|
3 | Prefiltering components. | |
4 |
|
4 | |||
5 | Prefilters transform user input before it is exec'd by Python. These |
|
5 | Prefilters transform user input before it is exec'd by Python. These | |
6 | transforms are used to implement additional syntax such as !ls and %magic. |
|
6 | transforms are used to implement additional syntax such as !ls and %magic. | |
7 |
|
7 | |||
8 | Authors: |
|
8 | Authors: | |
9 |
|
9 | |||
10 | * Brian Granger |
|
10 | * Brian Granger | |
11 | * Fernando Perez |
|
11 | * Fernando Perez | |
12 | * Dan Milstein |
|
12 | * Dan Milstein | |
13 | * Ville Vainio |
|
13 | * Ville Vainio | |
14 | """ |
|
14 | """ | |
15 |
|
15 | |||
16 | #----------------------------------------------------------------------------- |
|
16 | #----------------------------------------------------------------------------- | |
17 | # Copyright (C) 2008-2009 The IPython Development Team |
|
17 | # Copyright (C) 2008-2009 The IPython Development Team | |
18 | # |
|
18 | # | |
19 | # Distributed under the terms of the BSD License. The full license is in |
|
19 | # Distributed under the terms of the BSD License. The full license is in | |
20 | # the file COPYING, distributed as part of this software. |
|
20 | # the file COPYING, distributed as part of this software. | |
21 | #----------------------------------------------------------------------------- |
|
21 | #----------------------------------------------------------------------------- | |
22 |
|
22 | |||
23 | #----------------------------------------------------------------------------- |
|
23 | #----------------------------------------------------------------------------- | |
24 | # Imports |
|
24 | # Imports | |
25 | #----------------------------------------------------------------------------- |
|
25 | #----------------------------------------------------------------------------- | |
26 |
|
26 | |||
27 | import __builtin__ |
|
27 | import __builtin__ | |
28 | import codeop |
|
28 | import codeop | |
29 | import re |
|
29 | import re | |
30 |
|
30 | |||
31 | from IPython.core.alias import AliasManager |
|
31 | from IPython.core.alias import AliasManager | |
32 | from IPython.core.autocall import IPyAutocall |
|
32 | from IPython.core.autocall import IPyAutocall | |
33 | from IPython.config.configurable import Configurable |
|
33 | from IPython.config.configurable import Configurable | |
34 | from IPython.core.macro import Macro |
|
34 | from IPython.core.macro import Macro | |
35 | from IPython.core.splitinput import split_user_input |
|
35 | from IPython.core.splitinput import split_user_input | |
36 | from IPython.core import page |
|
36 | from IPython.core import page | |
37 |
|
37 | |||
38 | from IPython.utils.traitlets import List, Int, Any, Unicode, CBool, Bool, Instance |
|
38 | from IPython.utils.traitlets import List, Int, Any, Unicode, CBool, Bool, Instance | |
39 | from IPython.utils.text import make_quoted_expr |
|
39 | from IPython.utils.text import make_quoted_expr | |
40 | from IPython.utils.autoattr import auto_attr |
|
40 | from IPython.utils.autoattr import auto_attr | |
41 |
|
41 | |||
42 | #----------------------------------------------------------------------------- |
|
42 | #----------------------------------------------------------------------------- | |
43 | # Global utilities, errors and constants |
|
43 | # Global utilities, errors and constants | |
44 | #----------------------------------------------------------------------------- |
|
44 | #----------------------------------------------------------------------------- | |
45 |
|
45 | |||
46 | # Warning, these cannot be changed unless various regular expressions |
|
46 | # Warning, these cannot be changed unless various regular expressions | |
47 | # are updated in a number of places. Not great, but at least we told you. |
|
47 | # are updated in a number of places. Not great, but at least we told you. | |
48 | ESC_SHELL = '!' |
|
48 | ESC_SHELL = '!' | |
49 | ESC_SH_CAP = '!!' |
|
49 | ESC_SH_CAP = '!!' | |
50 | ESC_HELP = '?' |
|
50 | ESC_HELP = '?' | |
51 | ESC_MAGIC = '%' |
|
51 | ESC_MAGIC = '%' | |
52 | ESC_QUOTE = ',' |
|
52 | ESC_QUOTE = ',' | |
53 | ESC_QUOTE2 = ';' |
|
53 | ESC_QUOTE2 = ';' | |
54 | ESC_PAREN = '/' |
|
54 | ESC_PAREN = '/' | |
55 |
|
55 | |||
56 |
|
56 | |||
57 | class PrefilterError(Exception): |
|
57 | class PrefilterError(Exception): | |
58 | pass |
|
58 | pass | |
59 |
|
59 | |||
60 |
|
60 | |||
61 | # RegExp to identify potential function names |
|
61 | # RegExp to identify potential function names | |
62 | re_fun_name = re.compile(r'[a-zA-Z_]([a-zA-Z0-9_.]*) *$') |
|
62 | re_fun_name = re.compile(r'[a-zA-Z_]([a-zA-Z0-9_.]*) *$') | |
63 |
|
63 | |||
64 | # RegExp to exclude strings with this start from autocalling. In |
|
64 | # RegExp to exclude strings with this start from autocalling. In | |
65 | # particular, all binary operators should be excluded, so that if foo is |
|
65 | # particular, all binary operators should be excluded, so that if foo is | |
66 | # callable, foo OP bar doesn't become foo(OP bar), which is invalid. The |
|
66 | # callable, foo OP bar doesn't become foo(OP bar), which is invalid. The | |
67 | # characters '!=()' don't need to be checked for, as the checkPythonChars |
|
67 | # characters '!=()' don't need to be checked for, as the checkPythonChars | |
68 | # routine explicitely does so, to catch direct calls and rebindings of |
|
68 | # routine explicitely does so, to catch direct calls and rebindings of | |
69 | # existing names. |
|
69 | # existing names. | |
70 |
|
70 | |||
71 | # Warning: the '-' HAS TO BE AT THE END of the first group, otherwise |
|
71 | # Warning: the '-' HAS TO BE AT THE END of the first group, otherwise | |
72 | # it affects the rest of the group in square brackets. |
|
72 | # it affects the rest of the group in square brackets. | |
73 | re_exclude_auto = re.compile(r'^[,&^\|\*/\+-]' |
|
73 | re_exclude_auto = re.compile(r'^[,&^\|\*/\+-]' | |
74 | r'|^is |^not |^in |^and |^or ') |
|
74 | r'|^is |^not |^in |^and |^or ') | |
75 |
|
75 | |||
76 | # try to catch also methods for stuff in lists/tuples/dicts: off |
|
76 | # try to catch also methods for stuff in lists/tuples/dicts: off | |
77 | # (experimental). For this to work, the line_split regexp would need |
|
77 | # (experimental). For this to work, the line_split regexp would need | |
78 | # to be modified so it wouldn't break things at '['. That line is |
|
78 | # to be modified so it wouldn't break things at '['. That line is | |
79 | # nasty enough that I shouldn't change it until I can test it _well_. |
|
79 | # nasty enough that I shouldn't change it until I can test it _well_. | |
80 | #self.re_fun_name = re.compile (r'[a-zA-Z_]([a-zA-Z0-9_.\[\]]*) ?$') |
|
80 | #self.re_fun_name = re.compile (r'[a-zA-Z_]([a-zA-Z0-9_.\[\]]*) ?$') | |
81 |
|
81 | |||
82 |
|
82 | |||
83 | # Handler Check Utilities |
|
83 | # Handler Check Utilities | |
84 | def is_shadowed(identifier, ip): |
|
84 | def is_shadowed(identifier, ip): | |
85 | """Is the given identifier defined in one of the namespaces which shadow |
|
85 | """Is the given identifier defined in one of the namespaces which shadow | |
86 | the alias and magic namespaces? Note that an identifier is different |
|
86 | the alias and magic namespaces? Note that an identifier is different | |
87 | than ifun, because it can not contain a '.' character.""" |
|
87 | than ifun, because it can not contain a '.' character.""" | |
88 | # This is much safer than calling ofind, which can change state |
|
88 | # This is much safer than calling ofind, which can change state | |
89 | return (identifier in ip.user_ns \ |
|
89 | return (identifier in ip.user_ns \ | |
90 | or identifier in ip.internal_ns \ |
|
90 | or identifier in ip.internal_ns \ | |
91 | or identifier in ip.ns_table['builtin']) |
|
91 | or identifier in ip.ns_table['builtin']) | |
92 |
|
92 | |||
93 |
|
93 | |||
94 | #----------------------------------------------------------------------------- |
|
94 | #----------------------------------------------------------------------------- | |
95 | # The LineInfo class used throughout |
|
95 | # The LineInfo class used throughout | |
96 | #----------------------------------------------------------------------------- |
|
96 | #----------------------------------------------------------------------------- | |
97 |
|
97 | |||
98 |
|
98 | |||
99 | class LineInfo(object): |
|
99 | class LineInfo(object): | |
100 | """A single line of input and associated info. |
|
100 | """A single line of input and associated info. | |
101 |
|
101 | |||
102 | Includes the following as properties: |
|
102 | Includes the following as properties: | |
103 |
|
103 | |||
104 | line |
|
104 | line | |
105 | The original, raw line |
|
105 | The original, raw line | |
106 |
|
106 | |||
107 | continue_prompt |
|
107 | continue_prompt | |
108 | Is this line a continuation in a sequence of multiline input? |
|
108 | Is this line a continuation in a sequence of multiline input? | |
109 |
|
109 | |||
110 | pre |
|
110 | pre | |
111 | The initial esc character or whitespace. |
|
111 | The initial esc character or whitespace. | |
112 |
|
112 | |||
113 | pre_char |
|
113 | pre_char | |
114 | The escape character(s) in pre or the empty string if there isn't one. |
|
114 | The escape character(s) in pre or the empty string if there isn't one. | |
115 | Note that '!!' is a possible value for pre_char. Otherwise it will |
|
115 | Note that '!!' is a possible value for pre_char. Otherwise it will | |
116 | always be a single character. |
|
116 | always be a single character. | |
117 |
|
117 | |||
118 | pre_whitespace |
|
118 | pre_whitespace | |
119 | The leading whitespace from pre if it exists. If there is a pre_char, |
|
119 | The leading whitespace from pre if it exists. If there is a pre_char, | |
120 | this is just ''. |
|
120 | this is just ''. | |
121 |
|
121 | |||
122 | ifun |
|
122 | ifun | |
123 | The 'function part', which is basically the maximal initial sequence |
|
123 | The 'function part', which is basically the maximal initial sequence | |
124 | of valid python identifiers and the '.' character. This is what is |
|
124 | of valid python identifiers and the '.' character. This is what is | |
125 | checked for alias and magic transformations, used for auto-calling, |
|
125 | checked for alias and magic transformations, used for auto-calling, | |
126 | etc. |
|
126 | etc. | |
127 |
|
127 | |||
128 | the_rest |
|
128 | the_rest | |
129 | Everything else on the line. |
|
129 | Everything else on the line. | |
130 | """ |
|
130 | """ | |
131 | def __init__(self, line, continue_prompt): |
|
131 | def __init__(self, line, continue_prompt): | |
132 | self.line = line |
|
132 | self.line = line | |
133 | self.continue_prompt = continue_prompt |
|
133 | self.continue_prompt = continue_prompt | |
134 | self.pre, self.ifun, self.the_rest = split_user_input(line) |
|
134 | self.pre, self.esc, self.ifun, self.the_rest = split_user_input(line) | |
135 |
|
135 | |||
136 | self.pre_char = self.pre.strip() |
|
136 | self.pre_char = self.pre.strip() | |
137 | if self.pre_char: |
|
137 | if self.pre_char: | |
138 | self.pre_whitespace = '' # No whitespace allowd before esc chars |
|
138 | self.pre_whitespace = '' # No whitespace allowd before esc chars | |
139 | else: |
|
139 | else: | |
140 | self.pre_whitespace = self.pre |
|
140 | self.pre_whitespace = self.pre | |
141 |
|
141 | |||
142 | self._oinfo = None |
|
142 | self._oinfo = None | |
143 |
|
143 | |||
144 | def ofind(self, ip): |
|
144 | def ofind(self, ip): | |
145 | """Do a full, attribute-walking lookup of the ifun in the various |
|
145 | """Do a full, attribute-walking lookup of the ifun in the various | |
146 | namespaces for the given IPython InteractiveShell instance. |
|
146 | namespaces for the given IPython InteractiveShell instance. | |
147 |
|
147 | |||
148 | Return a dict with keys: found,obj,ospace,ismagic |
|
148 | Return a dict with keys: found,obj,ospace,ismagic | |
149 |
|
149 | |||
150 | Note: can cause state changes because of calling getattr, but should |
|
150 | Note: can cause state changes because of calling getattr, but should | |
151 | only be run if autocall is on and if the line hasn't matched any |
|
151 | only be run if autocall is on and if the line hasn't matched any | |
152 | other, less dangerous handlers. |
|
152 | other, less dangerous handlers. | |
153 |
|
153 | |||
154 | Does cache the results of the call, so can be called multiple times |
|
154 | Does cache the results of the call, so can be called multiple times | |
155 | without worrying about *further* damaging state. |
|
155 | without worrying about *further* damaging state. | |
156 | """ |
|
156 | """ | |
157 | if not self._oinfo: |
|
157 | if not self._oinfo: | |
158 | # ip.shell._ofind is actually on the Magic class! |
|
158 | # ip.shell._ofind is actually on the Magic class! | |
159 | self._oinfo = ip.shell._ofind(self.ifun) |
|
159 | self._oinfo = ip.shell._ofind(self.ifun) | |
160 | return self._oinfo |
|
160 | return self._oinfo | |
161 |
|
161 | |||
162 | def __str__(self): |
|
162 | def __str__(self): | |
163 | return "Lineinfo [%s|%s|%s]" %(self.pre, self.ifun, self.the_rest) |
|
163 | return "Lineinfo [%s|%s|%s]" %(self.pre, self.ifun, self.the_rest) | |
164 |
|
164 | |||
165 |
|
165 | |||
166 | #----------------------------------------------------------------------------- |
|
166 | #----------------------------------------------------------------------------- | |
167 | # Main Prefilter manager |
|
167 | # Main Prefilter manager | |
168 | #----------------------------------------------------------------------------- |
|
168 | #----------------------------------------------------------------------------- | |
169 |
|
169 | |||
170 |
|
170 | |||
171 | class PrefilterManager(Configurable): |
|
171 | class PrefilterManager(Configurable): | |
172 | """Main prefilter component. |
|
172 | """Main prefilter component. | |
173 |
|
173 | |||
174 | The IPython prefilter is run on all user input before it is run. The |
|
174 | The IPython prefilter is run on all user input before it is run. The | |
175 | prefilter consumes lines of input and produces transformed lines of |
|
175 | prefilter consumes lines of input and produces transformed lines of | |
176 | input. |
|
176 | input. | |
177 |
|
177 | |||
178 | The iplementation consists of two phases: |
|
178 | The iplementation consists of two phases: | |
179 |
|
179 | |||
180 | 1. Transformers |
|
180 | 1. Transformers | |
181 | 2. Checkers and handlers |
|
181 | 2. Checkers and handlers | |
182 |
|
182 | |||
183 | Over time, we plan on deprecating the checkers and handlers and doing |
|
183 | Over time, we plan on deprecating the checkers and handlers and doing | |
184 | everything in the transformers. |
|
184 | everything in the transformers. | |
185 |
|
185 | |||
186 | The transformers are instances of :class:`PrefilterTransformer` and have |
|
186 | The transformers are instances of :class:`PrefilterTransformer` and have | |
187 | a single method :meth:`transform` that takes a line and returns a |
|
187 | a single method :meth:`transform` that takes a line and returns a | |
188 | transformed line. The transformation can be accomplished using any |
|
188 | transformed line. The transformation can be accomplished using any | |
189 | tool, but our current ones use regular expressions for speed. We also |
|
189 | tool, but our current ones use regular expressions for speed. We also | |
190 | ship :mod:`pyparsing` in :mod:`IPython.external` for use in transformers. |
|
190 | ship :mod:`pyparsing` in :mod:`IPython.external` for use in transformers. | |
191 |
|
191 | |||
192 | After all the transformers have been run, the line is fed to the checkers, |
|
192 | After all the transformers have been run, the line is fed to the checkers, | |
193 | which are instances of :class:`PrefilterChecker`. The line is passed to |
|
193 | which are instances of :class:`PrefilterChecker`. The line is passed to | |
194 | the :meth:`check` method, which either returns `None` or a |
|
194 | the :meth:`check` method, which either returns `None` or a | |
195 | :class:`PrefilterHandler` instance. If `None` is returned, the other |
|
195 | :class:`PrefilterHandler` instance. If `None` is returned, the other | |
196 | checkers are tried. If an :class:`PrefilterHandler` instance is returned, |
|
196 | checkers are tried. If an :class:`PrefilterHandler` instance is returned, | |
197 | the line is passed to the :meth:`handle` method of the returned |
|
197 | the line is passed to the :meth:`handle` method of the returned | |
198 | handler and no further checkers are tried. |
|
198 | handler and no further checkers are tried. | |
199 |
|
199 | |||
200 | Both transformers and checkers have a `priority` attribute, that determines |
|
200 | Both transformers and checkers have a `priority` attribute, that determines | |
201 | the order in which they are called. Smaller priorities are tried first. |
|
201 | the order in which they are called. Smaller priorities are tried first. | |
202 |
|
202 | |||
203 | Both transformers and checkers also have `enabled` attribute, which is |
|
203 | Both transformers and checkers also have `enabled` attribute, which is | |
204 | a boolean that determines if the instance is used. |
|
204 | a boolean that determines if the instance is used. | |
205 |
|
205 | |||
206 | Users or developers can change the priority or enabled attribute of |
|
206 | Users or developers can change the priority or enabled attribute of | |
207 | transformers or checkers, but they must call the :meth:`sort_checkers` |
|
207 | transformers or checkers, but they must call the :meth:`sort_checkers` | |
208 | or :meth:`sort_transformers` method after changing the priority. |
|
208 | or :meth:`sort_transformers` method after changing the priority. | |
209 | """ |
|
209 | """ | |
210 |
|
210 | |||
211 | multi_line_specials = CBool(True, config=True) |
|
211 | multi_line_specials = CBool(True, config=True) | |
212 | shell = Instance('IPython.core.interactiveshell.InteractiveShellABC') |
|
212 | shell = Instance('IPython.core.interactiveshell.InteractiveShellABC') | |
213 |
|
213 | |||
214 | def __init__(self, shell=None, config=None): |
|
214 | def __init__(self, shell=None, config=None): | |
215 | super(PrefilterManager, self).__init__(shell=shell, config=config) |
|
215 | super(PrefilterManager, self).__init__(shell=shell, config=config) | |
216 | self.shell = shell |
|
216 | self.shell = shell | |
217 | self.init_transformers() |
|
217 | self.init_transformers() | |
218 | self.init_handlers() |
|
218 | self.init_handlers() | |
219 | self.init_checkers() |
|
219 | self.init_checkers() | |
220 |
|
220 | |||
221 | #------------------------------------------------------------------------- |
|
221 | #------------------------------------------------------------------------- | |
222 | # API for managing transformers |
|
222 | # API for managing transformers | |
223 | #------------------------------------------------------------------------- |
|
223 | #------------------------------------------------------------------------- | |
224 |
|
224 | |||
225 | def init_transformers(self): |
|
225 | def init_transformers(self): | |
226 | """Create the default transformers.""" |
|
226 | """Create the default transformers.""" | |
227 | self._transformers = [] |
|
227 | self._transformers = [] | |
228 | for transformer_cls in _default_transformers: |
|
228 | for transformer_cls in _default_transformers: | |
229 | transformer_cls( |
|
229 | transformer_cls( | |
230 | shell=self.shell, prefilter_manager=self, config=self.config |
|
230 | shell=self.shell, prefilter_manager=self, config=self.config | |
231 | ) |
|
231 | ) | |
232 |
|
232 | |||
233 | def sort_transformers(self): |
|
233 | def sort_transformers(self): | |
234 | """Sort the transformers by priority. |
|
234 | """Sort the transformers by priority. | |
235 |
|
235 | |||
236 | This must be called after the priority of a transformer is changed. |
|
236 | This must be called after the priority of a transformer is changed. | |
237 | The :meth:`register_transformer` method calls this automatically. |
|
237 | The :meth:`register_transformer` method calls this automatically. | |
238 | """ |
|
238 | """ | |
239 | self._transformers.sort(key=lambda x: x.priority) |
|
239 | self._transformers.sort(key=lambda x: x.priority) | |
240 |
|
240 | |||
241 | @property |
|
241 | @property | |
242 | def transformers(self): |
|
242 | def transformers(self): | |
243 | """Return a list of checkers, sorted by priority.""" |
|
243 | """Return a list of checkers, sorted by priority.""" | |
244 | return self._transformers |
|
244 | return self._transformers | |
245 |
|
245 | |||
246 | def register_transformer(self, transformer): |
|
246 | def register_transformer(self, transformer): | |
247 | """Register a transformer instance.""" |
|
247 | """Register a transformer instance.""" | |
248 | if transformer not in self._transformers: |
|
248 | if transformer not in self._transformers: | |
249 | self._transformers.append(transformer) |
|
249 | self._transformers.append(transformer) | |
250 | self.sort_transformers() |
|
250 | self.sort_transformers() | |
251 |
|
251 | |||
252 | def unregister_transformer(self, transformer): |
|
252 | def unregister_transformer(self, transformer): | |
253 | """Unregister a transformer instance.""" |
|
253 | """Unregister a transformer instance.""" | |
254 | if transformer in self._transformers: |
|
254 | if transformer in self._transformers: | |
255 | self._transformers.remove(transformer) |
|
255 | self._transformers.remove(transformer) | |
256 |
|
256 | |||
257 | #------------------------------------------------------------------------- |
|
257 | #------------------------------------------------------------------------- | |
258 | # API for managing checkers |
|
258 | # API for managing checkers | |
259 | #------------------------------------------------------------------------- |
|
259 | #------------------------------------------------------------------------- | |
260 |
|
260 | |||
261 | def init_checkers(self): |
|
261 | def init_checkers(self): | |
262 | """Create the default checkers.""" |
|
262 | """Create the default checkers.""" | |
263 | self._checkers = [] |
|
263 | self._checkers = [] | |
264 | for checker in _default_checkers: |
|
264 | for checker in _default_checkers: | |
265 | checker( |
|
265 | checker( | |
266 | shell=self.shell, prefilter_manager=self, config=self.config |
|
266 | shell=self.shell, prefilter_manager=self, config=self.config | |
267 | ) |
|
267 | ) | |
268 |
|
268 | |||
269 | def sort_checkers(self): |
|
269 | def sort_checkers(self): | |
270 | """Sort the checkers by priority. |
|
270 | """Sort the checkers by priority. | |
271 |
|
271 | |||
272 | This must be called after the priority of a checker is changed. |
|
272 | This must be called after the priority of a checker is changed. | |
273 | The :meth:`register_checker` method calls this automatically. |
|
273 | The :meth:`register_checker` method calls this automatically. | |
274 | """ |
|
274 | """ | |
275 | self._checkers.sort(key=lambda x: x.priority) |
|
275 | self._checkers.sort(key=lambda x: x.priority) | |
276 |
|
276 | |||
277 | @property |
|
277 | @property | |
278 | def checkers(self): |
|
278 | def checkers(self): | |
279 | """Return a list of checkers, sorted by priority.""" |
|
279 | """Return a list of checkers, sorted by priority.""" | |
280 | return self._checkers |
|
280 | return self._checkers | |
281 |
|
281 | |||
282 | def register_checker(self, checker): |
|
282 | def register_checker(self, checker): | |
283 | """Register a checker instance.""" |
|
283 | """Register a checker instance.""" | |
284 | if checker not in self._checkers: |
|
284 | if checker not in self._checkers: | |
285 | self._checkers.append(checker) |
|
285 | self._checkers.append(checker) | |
286 | self.sort_checkers() |
|
286 | self.sort_checkers() | |
287 |
|
287 | |||
288 | def unregister_checker(self, checker): |
|
288 | def unregister_checker(self, checker): | |
289 | """Unregister a checker instance.""" |
|
289 | """Unregister a checker instance.""" | |
290 | if checker in self._checkers: |
|
290 | if checker in self._checkers: | |
291 | self._checkers.remove(checker) |
|
291 | self._checkers.remove(checker) | |
292 |
|
292 | |||
293 | #------------------------------------------------------------------------- |
|
293 | #------------------------------------------------------------------------- | |
294 | # API for managing checkers |
|
294 | # API for managing checkers | |
295 | #------------------------------------------------------------------------- |
|
295 | #------------------------------------------------------------------------- | |
296 |
|
296 | |||
297 | def init_handlers(self): |
|
297 | def init_handlers(self): | |
298 | """Create the default handlers.""" |
|
298 | """Create the default handlers.""" | |
299 | self._handlers = {} |
|
299 | self._handlers = {} | |
300 | self._esc_handlers = {} |
|
300 | self._esc_handlers = {} | |
301 | for handler in _default_handlers: |
|
301 | for handler in _default_handlers: | |
302 | handler( |
|
302 | handler( | |
303 | shell=self.shell, prefilter_manager=self, config=self.config |
|
303 | shell=self.shell, prefilter_manager=self, config=self.config | |
304 | ) |
|
304 | ) | |
305 |
|
305 | |||
306 | @property |
|
306 | @property | |
307 | def handlers(self): |
|
307 | def handlers(self): | |
308 | """Return a dict of all the handlers.""" |
|
308 | """Return a dict of all the handlers.""" | |
309 | return self._handlers |
|
309 | return self._handlers | |
310 |
|
310 | |||
311 | def register_handler(self, name, handler, esc_strings): |
|
311 | def register_handler(self, name, handler, esc_strings): | |
312 | """Register a handler instance by name with esc_strings.""" |
|
312 | """Register a handler instance by name with esc_strings.""" | |
313 | self._handlers[name] = handler |
|
313 | self._handlers[name] = handler | |
314 | for esc_str in esc_strings: |
|
314 | for esc_str in esc_strings: | |
315 | self._esc_handlers[esc_str] = handler |
|
315 | self._esc_handlers[esc_str] = handler | |
316 |
|
316 | |||
317 | def unregister_handler(self, name, handler, esc_strings): |
|
317 | def unregister_handler(self, name, handler, esc_strings): | |
318 | """Unregister a handler instance by name with esc_strings.""" |
|
318 | """Unregister a handler instance by name with esc_strings.""" | |
319 | try: |
|
319 | try: | |
320 | del self._handlers[name] |
|
320 | del self._handlers[name] | |
321 | except KeyError: |
|
321 | except KeyError: | |
322 | pass |
|
322 | pass | |
323 | for esc_str in esc_strings: |
|
323 | for esc_str in esc_strings: | |
324 | h = self._esc_handlers.get(esc_str) |
|
324 | h = self._esc_handlers.get(esc_str) | |
325 | if h is handler: |
|
325 | if h is handler: | |
326 | del self._esc_handlers[esc_str] |
|
326 | del self._esc_handlers[esc_str] | |
327 |
|
327 | |||
328 | def get_handler_by_name(self, name): |
|
328 | def get_handler_by_name(self, name): | |
329 | """Get a handler by its name.""" |
|
329 | """Get a handler by its name.""" | |
330 | return self._handlers.get(name) |
|
330 | return self._handlers.get(name) | |
331 |
|
331 | |||
332 | def get_handler_by_esc(self, esc_str): |
|
332 | def get_handler_by_esc(self, esc_str): | |
333 | """Get a handler by its escape string.""" |
|
333 | """Get a handler by its escape string.""" | |
334 | return self._esc_handlers.get(esc_str) |
|
334 | return self._esc_handlers.get(esc_str) | |
335 |
|
335 | |||
336 | #------------------------------------------------------------------------- |
|
336 | #------------------------------------------------------------------------- | |
337 | # Main prefiltering API |
|
337 | # Main prefiltering API | |
338 | #------------------------------------------------------------------------- |
|
338 | #------------------------------------------------------------------------- | |
339 |
|
339 | |||
340 | def prefilter_line_info(self, line_info): |
|
340 | def prefilter_line_info(self, line_info): | |
341 | """Prefilter a line that has been converted to a LineInfo object. |
|
341 | """Prefilter a line that has been converted to a LineInfo object. | |
342 |
|
342 | |||
343 | This implements the checker/handler part of the prefilter pipe. |
|
343 | This implements the checker/handler part of the prefilter pipe. | |
344 | """ |
|
344 | """ | |
345 | # print "prefilter_line_info: ", line_info |
|
345 | # print "prefilter_line_info: ", line_info | |
346 | handler = self.find_handler(line_info) |
|
346 | handler = self.find_handler(line_info) | |
347 | return handler.handle(line_info) |
|
347 | return handler.handle(line_info) | |
348 |
|
348 | |||
349 | def find_handler(self, line_info): |
|
349 | def find_handler(self, line_info): | |
350 | """Find a handler for the line_info by trying checkers.""" |
|
350 | """Find a handler for the line_info by trying checkers.""" | |
351 | for checker in self.checkers: |
|
351 | for checker in self.checkers: | |
352 | if checker.enabled: |
|
352 | if checker.enabled: | |
353 | handler = checker.check(line_info) |
|
353 | handler = checker.check(line_info) | |
354 | if handler: |
|
354 | if handler: | |
355 | return handler |
|
355 | return handler | |
356 | return self.get_handler_by_name('normal') |
|
356 | return self.get_handler_by_name('normal') | |
357 |
|
357 | |||
358 | def transform_line(self, line, continue_prompt): |
|
358 | def transform_line(self, line, continue_prompt): | |
359 | """Calls the enabled transformers in order of increasing priority.""" |
|
359 | """Calls the enabled transformers in order of increasing priority.""" | |
360 | for transformer in self.transformers: |
|
360 | for transformer in self.transformers: | |
361 | if transformer.enabled: |
|
361 | if transformer.enabled: | |
362 | line = transformer.transform(line, continue_prompt) |
|
362 | line = transformer.transform(line, continue_prompt) | |
363 | return line |
|
363 | return line | |
364 |
|
364 | |||
365 | def prefilter_line(self, line, continue_prompt=False): |
|
365 | def prefilter_line(self, line, continue_prompt=False): | |
366 | """Prefilter a single input line as text. |
|
366 | """Prefilter a single input line as text. | |
367 |
|
367 | |||
368 | This method prefilters a single line of text by calling the |
|
368 | This method prefilters a single line of text by calling the | |
369 | transformers and then the checkers/handlers. |
|
369 | transformers and then the checkers/handlers. | |
370 | """ |
|
370 | """ | |
371 |
|
371 | |||
372 | # print "prefilter_line: ", line, continue_prompt |
|
372 | # print "prefilter_line: ", line, continue_prompt | |
373 | # All handlers *must* return a value, even if it's blank (''). |
|
373 | # All handlers *must* return a value, even if it's blank (''). | |
374 |
|
374 | |||
375 | # save the line away in case we crash, so the post-mortem handler can |
|
375 | # save the line away in case we crash, so the post-mortem handler can | |
376 | # record it |
|
376 | # record it | |
377 | self.shell._last_input_line = line |
|
377 | self.shell._last_input_line = line | |
378 |
|
378 | |||
379 | if not line: |
|
379 | if not line: | |
380 | # Return immediately on purely empty lines, so that if the user |
|
380 | # Return immediately on purely empty lines, so that if the user | |
381 | # previously typed some whitespace that started a continuation |
|
381 | # previously typed some whitespace that started a continuation | |
382 | # prompt, he can break out of that loop with just an empty line. |
|
382 | # prompt, he can break out of that loop with just an empty line. | |
383 | # This is how the default python prompt works. |
|
383 | # This is how the default python prompt works. | |
384 | return '' |
|
384 | return '' | |
385 |
|
385 | |||
386 | # At this point, we invoke our transformers. |
|
386 | # At this point, we invoke our transformers. | |
387 | if not continue_prompt or (continue_prompt and self.multi_line_specials): |
|
387 | if not continue_prompt or (continue_prompt and self.multi_line_specials): | |
388 | line = self.transform_line(line, continue_prompt) |
|
388 | line = self.transform_line(line, continue_prompt) | |
389 |
|
389 | |||
390 | # Now we compute line_info for the checkers and handlers |
|
390 | # Now we compute line_info for the checkers and handlers | |
391 | line_info = LineInfo(line, continue_prompt) |
|
391 | line_info = LineInfo(line, continue_prompt) | |
392 |
|
392 | |||
393 | # the input history needs to track even empty lines |
|
393 | # the input history needs to track even empty lines | |
394 | stripped = line.strip() |
|
394 | stripped = line.strip() | |
395 |
|
395 | |||
396 | normal_handler = self.get_handler_by_name('normal') |
|
396 | normal_handler = self.get_handler_by_name('normal') | |
397 | if not stripped: |
|
397 | if not stripped: | |
398 | if not continue_prompt: |
|
398 | if not continue_prompt: | |
399 | self.shell.displayhook.prompt_count -= 1 |
|
399 | self.shell.displayhook.prompt_count -= 1 | |
400 |
|
400 | |||
401 | return normal_handler.handle(line_info) |
|
401 | return normal_handler.handle(line_info) | |
402 |
|
402 | |||
403 | # special handlers are only allowed for single line statements |
|
403 | # special handlers are only allowed for single line statements | |
404 | if continue_prompt and not self.multi_line_specials: |
|
404 | if continue_prompt and not self.multi_line_specials: | |
405 | return normal_handler.handle(line_info) |
|
405 | return normal_handler.handle(line_info) | |
406 |
|
406 | |||
407 | prefiltered = self.prefilter_line_info(line_info) |
|
407 | prefiltered = self.prefilter_line_info(line_info) | |
408 | # print "prefiltered line: %r" % prefiltered |
|
408 | # print "prefiltered line: %r" % prefiltered | |
409 | return prefiltered |
|
409 | return prefiltered | |
410 |
|
410 | |||
411 | def prefilter_lines(self, lines, continue_prompt=False): |
|
411 | def prefilter_lines(self, lines, continue_prompt=False): | |
412 | """Prefilter multiple input lines of text. |
|
412 | """Prefilter multiple input lines of text. | |
413 |
|
413 | |||
414 | This is the main entry point for prefiltering multiple lines of |
|
414 | This is the main entry point for prefiltering multiple lines of | |
415 | input. This simply calls :meth:`prefilter_line` for each line of |
|
415 | input. This simply calls :meth:`prefilter_line` for each line of | |
416 | input. |
|
416 | input. | |
417 |
|
417 | |||
418 | This covers cases where there are multiple lines in the user entry, |
|
418 | This covers cases where there are multiple lines in the user entry, | |
419 | which is the case when the user goes back to a multiline history |
|
419 | which is the case when the user goes back to a multiline history | |
420 | entry and presses enter. |
|
420 | entry and presses enter. | |
421 | """ |
|
421 | """ | |
422 | llines = lines.rstrip('\n').split('\n') |
|
422 | llines = lines.rstrip('\n').split('\n') | |
423 | # We can get multiple lines in one shot, where multiline input 'blends' |
|
423 | # We can get multiple lines in one shot, where multiline input 'blends' | |
424 | # into one line, in cases like recalling from the readline history |
|
424 | # into one line, in cases like recalling from the readline history | |
425 | # buffer. We need to make sure that in such cases, we correctly |
|
425 | # buffer. We need to make sure that in such cases, we correctly | |
426 | # communicate downstream which line is first and which are continuation |
|
426 | # communicate downstream which line is first and which are continuation | |
427 | # ones. |
|
427 | # ones. | |
428 | if len(llines) > 1: |
|
428 | if len(llines) > 1: | |
429 | out = '\n'.join([self.prefilter_line(line, lnum>0) |
|
429 | out = '\n'.join([self.prefilter_line(line, lnum>0) | |
430 | for lnum, line in enumerate(llines) ]) |
|
430 | for lnum, line in enumerate(llines) ]) | |
431 | else: |
|
431 | else: | |
432 | out = self.prefilter_line(llines[0], continue_prompt) |
|
432 | out = self.prefilter_line(llines[0], continue_prompt) | |
433 |
|
433 | |||
434 | return out |
|
434 | return out | |
435 |
|
435 | |||
436 | #----------------------------------------------------------------------------- |
|
436 | #----------------------------------------------------------------------------- | |
437 | # Prefilter transformers |
|
437 | # Prefilter transformers | |
438 | #----------------------------------------------------------------------------- |
|
438 | #----------------------------------------------------------------------------- | |
439 |
|
439 | |||
440 |
|
440 | |||
441 | class PrefilterTransformer(Configurable): |
|
441 | class PrefilterTransformer(Configurable): | |
442 | """Transform a line of user input.""" |
|
442 | """Transform a line of user input.""" | |
443 |
|
443 | |||
444 | priority = Int(100, config=True) |
|
444 | priority = Int(100, config=True) | |
445 | # Transformers don't currently use shell or prefilter_manager, but as we |
|
445 | # Transformers don't currently use shell or prefilter_manager, but as we | |
446 | # move away from checkers and handlers, they will need them. |
|
446 | # move away from checkers and handlers, they will need them. | |
447 | shell = Instance('IPython.core.interactiveshell.InteractiveShellABC') |
|
447 | shell = Instance('IPython.core.interactiveshell.InteractiveShellABC') | |
448 | prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager') |
|
448 | prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager') | |
449 | enabled = Bool(True, config=True) |
|
449 | enabled = Bool(True, config=True) | |
450 |
|
450 | |||
451 | def __init__(self, shell=None, prefilter_manager=None, config=None): |
|
451 | def __init__(self, shell=None, prefilter_manager=None, config=None): | |
452 | super(PrefilterTransformer, self).__init__( |
|
452 | super(PrefilterTransformer, self).__init__( | |
453 | shell=shell, prefilter_manager=prefilter_manager, config=config |
|
453 | shell=shell, prefilter_manager=prefilter_manager, config=config | |
454 | ) |
|
454 | ) | |
455 | self.prefilter_manager.register_transformer(self) |
|
455 | self.prefilter_manager.register_transformer(self) | |
456 |
|
456 | |||
457 | def transform(self, line, continue_prompt): |
|
457 | def transform(self, line, continue_prompt): | |
458 | """Transform a line, returning the new one.""" |
|
458 | """Transform a line, returning the new one.""" | |
459 | return None |
|
459 | return None | |
460 |
|
460 | |||
461 | def __repr__(self): |
|
461 | def __repr__(self): | |
462 | return "<%s(priority=%r, enabled=%r)>" % ( |
|
462 | return "<%s(priority=%r, enabled=%r)>" % ( | |
463 | self.__class__.__name__, self.priority, self.enabled) |
|
463 | self.__class__.__name__, self.priority, self.enabled) | |
464 |
|
464 | |||
465 |
|
465 | |||
466 | _assign_system_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))' |
|
466 | _assign_system_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))' | |
467 | r'\s*=\s*!(?P<cmd>.*)') |
|
467 | r'\s*=\s*!(?P<cmd>.*)') | |
468 |
|
468 | |||
469 |
|
469 | |||
470 | class AssignSystemTransformer(PrefilterTransformer): |
|
470 | class AssignSystemTransformer(PrefilterTransformer): | |
471 | """Handle the `files = !ls` syntax.""" |
|
471 | """Handle the `files = !ls` syntax.""" | |
472 |
|
472 | |||
473 | priority = Int(100, config=True) |
|
473 | priority = Int(100, config=True) | |
474 |
|
474 | |||
475 | def transform(self, line, continue_prompt): |
|
475 | def transform(self, line, continue_prompt): | |
476 | m = _assign_system_re.match(line) |
|
476 | m = _assign_system_re.match(line) | |
477 | if m is not None: |
|
477 | if m is not None: | |
478 | cmd = m.group('cmd') |
|
478 | cmd = m.group('cmd') | |
479 | lhs = m.group('lhs') |
|
479 | lhs = m.group('lhs') | |
480 | expr = make_quoted_expr("sc =%s" % cmd) |
|
480 | expr = make_quoted_expr("sc =%s" % cmd) | |
481 | new_line = '%s = get_ipython().magic(%s)' % (lhs, expr) |
|
481 | new_line = '%s = get_ipython().magic(%s)' % (lhs, expr) | |
482 | return new_line |
|
482 | return new_line | |
483 | return line |
|
483 | return line | |
484 |
|
484 | |||
485 |
|
485 | |||
486 | _assign_magic_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))' |
|
486 | _assign_magic_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))' | |
487 | r'\s*=\s*%(?P<cmd>.*)') |
|
487 | r'\s*=\s*%(?P<cmd>.*)') | |
488 |
|
488 | |||
489 | class AssignMagicTransformer(PrefilterTransformer): |
|
489 | class AssignMagicTransformer(PrefilterTransformer): | |
490 | """Handle the `a = %who` syntax.""" |
|
490 | """Handle the `a = %who` syntax.""" | |
491 |
|
491 | |||
492 | priority = Int(200, config=True) |
|
492 | priority = Int(200, config=True) | |
493 |
|
493 | |||
494 | def transform(self, line, continue_prompt): |
|
494 | def transform(self, line, continue_prompt): | |
495 | m = _assign_magic_re.match(line) |
|
495 | m = _assign_magic_re.match(line) | |
496 | if m is not None: |
|
496 | if m is not None: | |
497 | cmd = m.group('cmd') |
|
497 | cmd = m.group('cmd') | |
498 | lhs = m.group('lhs') |
|
498 | lhs = m.group('lhs') | |
499 | expr = make_quoted_expr(cmd) |
|
499 | expr = make_quoted_expr(cmd) | |
500 | new_line = '%s = get_ipython().magic(%s)' % (lhs, expr) |
|
500 | new_line = '%s = get_ipython().magic(%s)' % (lhs, expr) | |
501 | return new_line |
|
501 | return new_line | |
502 | return line |
|
502 | return line | |
503 |
|
503 | |||
504 |
|
504 | |||
505 | _classic_prompt_re = re.compile(r'(^[ \t]*>>> |^[ \t]*\.\.\. )') |
|
505 | _classic_prompt_re = re.compile(r'(^[ \t]*>>> |^[ \t]*\.\.\. )') | |
506 |
|
506 | |||
507 | class PyPromptTransformer(PrefilterTransformer): |
|
507 | class PyPromptTransformer(PrefilterTransformer): | |
508 | """Handle inputs that start with '>>> ' syntax.""" |
|
508 | """Handle inputs that start with '>>> ' syntax.""" | |
509 |
|
509 | |||
510 | priority = Int(50, config=True) |
|
510 | priority = Int(50, config=True) | |
511 |
|
511 | |||
512 | def transform(self, line, continue_prompt): |
|
512 | def transform(self, line, continue_prompt): | |
513 |
|
513 | |||
514 | if not line or line.isspace() or line.strip() == '...': |
|
514 | if not line or line.isspace() or line.strip() == '...': | |
515 | # This allows us to recognize multiple input prompts separated by |
|
515 | # This allows us to recognize multiple input prompts separated by | |
516 | # blank lines and pasted in a single chunk, very common when |
|
516 | # blank lines and pasted in a single chunk, very common when | |
517 | # pasting doctests or long tutorial passages. |
|
517 | # pasting doctests or long tutorial passages. | |
518 | return '' |
|
518 | return '' | |
519 | m = _classic_prompt_re.match(line) |
|
519 | m = _classic_prompt_re.match(line) | |
520 | if m: |
|
520 | if m: | |
521 | return line[len(m.group(0)):] |
|
521 | return line[len(m.group(0)):] | |
522 | else: |
|
522 | else: | |
523 | return line |
|
523 | return line | |
524 |
|
524 | |||
525 |
|
525 | |||
526 | _ipy_prompt_re = re.compile(r'(^[ \t]*In \[\d+\]: |^[ \t]*\ \ \ \.\.\.+: )') |
|
526 | _ipy_prompt_re = re.compile(r'(^[ \t]*In \[\d+\]: |^[ \t]*\ \ \ \.\.\.+: )') | |
527 |
|
527 | |||
528 | class IPyPromptTransformer(PrefilterTransformer): |
|
528 | class IPyPromptTransformer(PrefilterTransformer): | |
529 | """Handle inputs that start classic IPython prompt syntax.""" |
|
529 | """Handle inputs that start classic IPython prompt syntax.""" | |
530 |
|
530 | |||
531 | priority = Int(50, config=True) |
|
531 | priority = Int(50, config=True) | |
532 |
|
532 | |||
533 | def transform(self, line, continue_prompt): |
|
533 | def transform(self, line, continue_prompt): | |
534 |
|
534 | |||
535 | if not line or line.isspace() or line.strip() == '...': |
|
535 | if not line or line.isspace() or line.strip() == '...': | |
536 | # This allows us to recognize multiple input prompts separated by |
|
536 | # This allows us to recognize multiple input prompts separated by | |
537 | # blank lines and pasted in a single chunk, very common when |
|
537 | # blank lines and pasted in a single chunk, very common when | |
538 | # pasting doctests or long tutorial passages. |
|
538 | # pasting doctests or long tutorial passages. | |
539 | return '' |
|
539 | return '' | |
540 | m = _ipy_prompt_re.match(line) |
|
540 | m = _ipy_prompt_re.match(line) | |
541 | if m: |
|
541 | if m: | |
542 | return line[len(m.group(0)):] |
|
542 | return line[len(m.group(0)):] | |
543 | else: |
|
543 | else: | |
544 | return line |
|
544 | return line | |
545 |
|
545 | |||
546 | #----------------------------------------------------------------------------- |
|
546 | #----------------------------------------------------------------------------- | |
547 | # Prefilter checkers |
|
547 | # Prefilter checkers | |
548 | #----------------------------------------------------------------------------- |
|
548 | #----------------------------------------------------------------------------- | |
549 |
|
549 | |||
550 |
|
550 | |||
551 | class PrefilterChecker(Configurable): |
|
551 | class PrefilterChecker(Configurable): | |
552 | """Inspect an input line and return a handler for that line.""" |
|
552 | """Inspect an input line and return a handler for that line.""" | |
553 |
|
553 | |||
554 | priority = Int(100, config=True) |
|
554 | priority = Int(100, config=True) | |
555 | shell = Instance('IPython.core.interactiveshell.InteractiveShellABC') |
|
555 | shell = Instance('IPython.core.interactiveshell.InteractiveShellABC') | |
556 | prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager') |
|
556 | prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager') | |
557 | enabled = Bool(True, config=True) |
|
557 | enabled = Bool(True, config=True) | |
558 |
|
558 | |||
559 | def __init__(self, shell=None, prefilter_manager=None, config=None): |
|
559 | def __init__(self, shell=None, prefilter_manager=None, config=None): | |
560 | super(PrefilterChecker, self).__init__( |
|
560 | super(PrefilterChecker, self).__init__( | |
561 | shell=shell, prefilter_manager=prefilter_manager, config=config |
|
561 | shell=shell, prefilter_manager=prefilter_manager, config=config | |
562 | ) |
|
562 | ) | |
563 | self.prefilter_manager.register_checker(self) |
|
563 | self.prefilter_manager.register_checker(self) | |
564 |
|
564 | |||
565 | def check(self, line_info): |
|
565 | def check(self, line_info): | |
566 | """Inspect line_info and return a handler instance or None.""" |
|
566 | """Inspect line_info and return a handler instance or None.""" | |
567 | return None |
|
567 | return None | |
568 |
|
568 | |||
569 | def __repr__(self): |
|
569 | def __repr__(self): | |
570 | return "<%s(priority=%r, enabled=%r)>" % ( |
|
570 | return "<%s(priority=%r, enabled=%r)>" % ( | |
571 | self.__class__.__name__, self.priority, self.enabled) |
|
571 | self.__class__.__name__, self.priority, self.enabled) | |
572 |
|
572 | |||
573 |
|
573 | |||
574 | class EmacsChecker(PrefilterChecker): |
|
574 | class EmacsChecker(PrefilterChecker): | |
575 |
|
575 | |||
576 | priority = Int(100, config=True) |
|
576 | priority = Int(100, config=True) | |
577 | enabled = Bool(False, config=True) |
|
577 | enabled = Bool(False, config=True) | |
578 |
|
578 | |||
579 | def check(self, line_info): |
|
579 | def check(self, line_info): | |
580 | "Emacs ipython-mode tags certain input lines." |
|
580 | "Emacs ipython-mode tags certain input lines." | |
581 | if line_info.line.endswith('# PYTHON-MODE'): |
|
581 | if line_info.line.endswith('# PYTHON-MODE'): | |
582 | return self.prefilter_manager.get_handler_by_name('emacs') |
|
582 | return self.prefilter_manager.get_handler_by_name('emacs') | |
583 | else: |
|
583 | else: | |
584 | return None |
|
584 | return None | |
585 |
|
585 | |||
586 |
|
586 | |||
587 | class ShellEscapeChecker(PrefilterChecker): |
|
587 | class ShellEscapeChecker(PrefilterChecker): | |
588 |
|
588 | |||
589 | priority = Int(200, config=True) |
|
589 | priority = Int(200, config=True) | |
590 |
|
590 | |||
591 | def check(self, line_info): |
|
591 | def check(self, line_info): | |
592 | if line_info.line.lstrip().startswith(ESC_SHELL): |
|
592 | if line_info.line.lstrip().startswith(ESC_SHELL): | |
593 | return self.prefilter_manager.get_handler_by_name('shell') |
|
593 | return self.prefilter_manager.get_handler_by_name('shell') | |
594 |
|
594 | |||
595 |
|
595 | |||
596 | class MacroChecker(PrefilterChecker): |
|
596 | class MacroChecker(PrefilterChecker): | |
597 |
|
597 | |||
598 | priority = Int(250, config=True) |
|
598 | priority = Int(250, config=True) | |
599 |
|
599 | |||
600 | def check(self, line_info): |
|
600 | def check(self, line_info): | |
601 | obj = self.shell.user_ns.get(line_info.ifun) |
|
601 | obj = self.shell.user_ns.get(line_info.ifun) | |
602 | if isinstance(obj, Macro): |
|
602 | if isinstance(obj, Macro): | |
603 | return self.prefilter_manager.get_handler_by_name('macro') |
|
603 | return self.prefilter_manager.get_handler_by_name('macro') | |
604 | else: |
|
604 | else: | |
605 | return None |
|
605 | return None | |
606 |
|
606 | |||
607 |
|
607 | |||
608 | class IPyAutocallChecker(PrefilterChecker): |
|
608 | class IPyAutocallChecker(PrefilterChecker): | |
609 |
|
609 | |||
610 | priority = Int(300, config=True) |
|
610 | priority = Int(300, config=True) | |
611 |
|
611 | |||
612 | def check(self, line_info): |
|
612 | def check(self, line_info): | |
613 | "Instances of IPyAutocall in user_ns get autocalled immediately" |
|
613 | "Instances of IPyAutocall in user_ns get autocalled immediately" | |
614 | obj = self.shell.user_ns.get(line_info.ifun, None) |
|
614 | obj = self.shell.user_ns.get(line_info.ifun, None) | |
615 | if isinstance(obj, IPyAutocall): |
|
615 | if isinstance(obj, IPyAutocall): | |
616 | obj.set_ip(self.shell) |
|
616 | obj.set_ip(self.shell) | |
617 | return self.prefilter_manager.get_handler_by_name('auto') |
|
617 | return self.prefilter_manager.get_handler_by_name('auto') | |
618 | else: |
|
618 | else: | |
619 | return None |
|
619 | return None | |
620 |
|
620 | |||
621 |
|
621 | |||
622 | class MultiLineMagicChecker(PrefilterChecker): |
|
622 | class MultiLineMagicChecker(PrefilterChecker): | |
623 |
|
623 | |||
624 | priority = Int(400, config=True) |
|
624 | priority = Int(400, config=True) | |
625 |
|
625 | |||
626 | def check(self, line_info): |
|
626 | def check(self, line_info): | |
627 | "Allow ! and !! in multi-line statements if multi_line_specials is on" |
|
627 | "Allow ! and !! in multi-line statements if multi_line_specials is on" | |
628 | # Note that this one of the only places we check the first character of |
|
628 | # Note that this one of the only places we check the first character of | |
629 | # ifun and *not* the pre_char. Also note that the below test matches |
|
629 | # ifun and *not* the pre_char. Also note that the below test matches | |
630 | # both ! and !!. |
|
630 | # both ! and !!. | |
631 | if line_info.continue_prompt \ |
|
631 | if line_info.continue_prompt \ | |
632 | and self.prefilter_manager.multi_line_specials: |
|
632 | and self.prefilter_manager.multi_line_specials: | |
633 |
if line_info. |
|
633 | if line_info.esc == ESC_MAGIC: | |
634 | return self.prefilter_manager.get_handler_by_name('magic') |
|
634 | return self.prefilter_manager.get_handler_by_name('magic') | |
635 | else: |
|
635 | else: | |
636 | return None |
|
636 | return None | |
637 |
|
637 | |||
638 |
|
638 | |||
639 | class EscCharsChecker(PrefilterChecker): |
|
639 | class EscCharsChecker(PrefilterChecker): | |
640 |
|
640 | |||
641 | priority = Int(500, config=True) |
|
641 | priority = Int(500, config=True) | |
642 |
|
642 | |||
643 | def check(self, line_info): |
|
643 | def check(self, line_info): | |
644 | """Check for escape character and return either a handler to handle it, |
|
644 | """Check for escape character and return either a handler to handle it, | |
645 | or None if there is no escape char.""" |
|
645 | or None if there is no escape char.""" | |
646 | if line_info.line[-1] == ESC_HELP \ |
|
646 | if line_info.line[-1] == ESC_HELP \ | |
647 |
and line_info. |
|
647 | and line_info.esc != ESC_SHELL \ | |
648 |
and line_info. |
|
648 | and line_info.esc != ESC_SH_CAP: | |
649 | # the ? can be at the end, but *not* for either kind of shell escape, |
|
649 | # the ? can be at the end, but *not* for either kind of shell escape, | |
650 | # because a ? can be a vaild final char in a shell cmd |
|
650 | # because a ? can be a vaild final char in a shell cmd | |
651 | return self.prefilter_manager.get_handler_by_name('help') |
|
651 | return self.prefilter_manager.get_handler_by_name('help') | |
652 | else: |
|
652 | else: | |
|
653 | if line_info.pre: | |||
|
654 | return None | |||
653 | # This returns None like it should if no handler exists |
|
655 | # This returns None like it should if no handler exists | |
654 |
return self.prefilter_manager.get_handler_by_esc(line_info. |
|
656 | return self.prefilter_manager.get_handler_by_esc(line_info.esc) | |
655 |
|
657 | |||
656 |
|
658 | |||
657 | class AssignmentChecker(PrefilterChecker): |
|
659 | class AssignmentChecker(PrefilterChecker): | |
658 |
|
660 | |||
659 | priority = Int(600, config=True) |
|
661 | priority = Int(600, config=True) | |
660 |
|
662 | |||
661 | def check(self, line_info): |
|
663 | def check(self, line_info): | |
662 | """Check to see if user is assigning to a var for the first time, in |
|
664 | """Check to see if user is assigning to a var for the first time, in | |
663 | which case we want to avoid any sort of automagic / autocall games. |
|
665 | which case we want to avoid any sort of automagic / autocall games. | |
664 |
|
666 | |||
665 | This allows users to assign to either alias or magic names true python |
|
667 | This allows users to assign to either alias or magic names true python | |
666 | variables (the magic/alias systems always take second seat to true |
|
668 | variables (the magic/alias systems always take second seat to true | |
667 | python code). E.g. ls='hi', or ls,that=1,2""" |
|
669 | python code). E.g. ls='hi', or ls,that=1,2""" | |
668 | if line_info.the_rest: |
|
670 | if line_info.the_rest: | |
669 | if line_info.the_rest[0] in '=,': |
|
671 | if line_info.the_rest[0] in '=,': | |
670 | return self.prefilter_manager.get_handler_by_name('normal') |
|
672 | return self.prefilter_manager.get_handler_by_name('normal') | |
671 | else: |
|
673 | else: | |
672 | return None |
|
674 | return None | |
673 |
|
675 | |||
674 |
|
676 | |||
675 | class AutoMagicChecker(PrefilterChecker): |
|
677 | class AutoMagicChecker(PrefilterChecker): | |
676 |
|
678 | |||
677 | priority = Int(700, config=True) |
|
679 | priority = Int(700, config=True) | |
678 |
|
680 | |||
679 | def check(self, line_info): |
|
681 | def check(self, line_info): | |
680 | """If the ifun is magic, and automagic is on, run it. Note: normal, |
|
682 | """If the ifun is magic, and automagic is on, run it. Note: normal, | |
681 | non-auto magic would already have been triggered via '%' in |
|
683 | non-auto magic would already have been triggered via '%' in | |
682 | check_esc_chars. This just checks for automagic. Also, before |
|
684 | check_esc_chars. This just checks for automagic. Also, before | |
683 | triggering the magic handler, make sure that there is nothing in the |
|
685 | triggering the magic handler, make sure that there is nothing in the | |
684 | user namespace which could shadow it.""" |
|
686 | user namespace which could shadow it.""" | |
685 | if not self.shell.automagic or not hasattr(self.shell,'magic_'+line_info.ifun): |
|
687 | if not self.shell.automagic or not hasattr(self.shell,'magic_'+line_info.ifun): | |
686 | return None |
|
688 | return None | |
687 |
|
689 | |||
688 | # We have a likely magic method. Make sure we should actually call it. |
|
690 | # We have a likely magic method. Make sure we should actually call it. | |
689 | if line_info.continue_prompt and not self.prefilter_manager.multi_line_specials: |
|
691 | if line_info.continue_prompt and not self.prefilter_manager.multi_line_specials: | |
690 | return None |
|
692 | return None | |
691 |
|
693 | |||
692 | head = line_info.ifun.split('.',1)[0] |
|
694 | head = line_info.ifun.split('.',1)[0] | |
693 | if is_shadowed(head, self.shell): |
|
695 | if is_shadowed(head, self.shell): | |
694 | return None |
|
696 | return None | |
695 |
|
697 | |||
696 | return self.prefilter_manager.get_handler_by_name('magic') |
|
698 | return self.prefilter_manager.get_handler_by_name('magic') | |
697 |
|
699 | |||
698 |
|
700 | |||
699 | class AliasChecker(PrefilterChecker): |
|
701 | class AliasChecker(PrefilterChecker): | |
700 |
|
702 | |||
701 | priority = Int(800, config=True) |
|
703 | priority = Int(800, config=True) | |
702 |
|
704 | |||
703 | def check(self, line_info): |
|
705 | def check(self, line_info): | |
704 | "Check if the initital identifier on the line is an alias." |
|
706 | "Check if the initital identifier on the line is an alias." | |
705 | # Note: aliases can not contain '.' |
|
707 | # Note: aliases can not contain '.' | |
706 | head = line_info.ifun.split('.',1)[0] |
|
708 | head = line_info.ifun.split('.',1)[0] | |
707 | if line_info.ifun not in self.shell.alias_manager \ |
|
709 | if line_info.ifun not in self.shell.alias_manager \ | |
708 | or head not in self.shell.alias_manager \ |
|
710 | or head not in self.shell.alias_manager \ | |
709 | or is_shadowed(head, self.shell): |
|
711 | or is_shadowed(head, self.shell): | |
710 | return None |
|
712 | return None | |
711 |
|
713 | |||
712 | return self.prefilter_manager.get_handler_by_name('alias') |
|
714 | return self.prefilter_manager.get_handler_by_name('alias') | |
713 |
|
715 | |||
714 |
|
716 | |||
715 | class PythonOpsChecker(PrefilterChecker): |
|
717 | class PythonOpsChecker(PrefilterChecker): | |
716 |
|
718 | |||
717 | priority = Int(900, config=True) |
|
719 | priority = Int(900, config=True) | |
718 |
|
720 | |||
719 | def check(self, line_info): |
|
721 | def check(self, line_info): | |
720 | """If the 'rest' of the line begins with a function call or pretty much |
|
722 | """If the 'rest' of the line begins with a function call or pretty much | |
721 | any python operator, we should simply execute the line (regardless of |
|
723 | any python operator, we should simply execute the line (regardless of | |
722 | whether or not there's a possible autocall expansion). This avoids |
|
724 | whether or not there's a possible autocall expansion). This avoids | |
723 | spurious (and very confusing) geattr() accesses.""" |
|
725 | spurious (and very confusing) geattr() accesses.""" | |
724 | if line_info.the_rest and line_info.the_rest[0] in '!=()<>,+*/%^&|': |
|
726 | if line_info.the_rest and line_info.the_rest[0] in '!=()<>,+*/%^&|': | |
725 | return self.prefilter_manager.get_handler_by_name('normal') |
|
727 | return self.prefilter_manager.get_handler_by_name('normal') | |
726 | else: |
|
728 | else: | |
727 | return None |
|
729 | return None | |
728 |
|
730 | |||
729 |
|
731 | |||
730 | class AutocallChecker(PrefilterChecker): |
|
732 | class AutocallChecker(PrefilterChecker): | |
731 |
|
733 | |||
732 | priority = Int(1000, config=True) |
|
734 | priority = Int(1000, config=True) | |
733 |
|
735 | |||
734 | def check(self, line_info): |
|
736 | def check(self, line_info): | |
735 | "Check if the initial word/function is callable and autocall is on." |
|
737 | "Check if the initial word/function is callable and autocall is on." | |
736 | if not self.shell.autocall: |
|
738 | if not self.shell.autocall: | |
737 | return None |
|
739 | return None | |
738 |
|
740 | |||
739 | oinfo = line_info.ofind(self.shell) # This can mutate state via getattr |
|
741 | oinfo = line_info.ofind(self.shell) # This can mutate state via getattr | |
740 | if not oinfo['found']: |
|
742 | if not oinfo['found']: | |
741 | return None |
|
743 | return None | |
742 |
|
744 | |||
743 | if callable(oinfo['obj']) \ |
|
745 | if callable(oinfo['obj']) \ | |
744 | and (not re_exclude_auto.match(line_info.the_rest)) \ |
|
746 | and (not re_exclude_auto.match(line_info.the_rest)) \ | |
745 | and re_fun_name.match(line_info.ifun): |
|
747 | and re_fun_name.match(line_info.ifun): | |
746 | return self.prefilter_manager.get_handler_by_name('auto') |
|
748 | return self.prefilter_manager.get_handler_by_name('auto') | |
747 | else: |
|
749 | else: | |
748 | return None |
|
750 | return None | |
749 |
|
751 | |||
750 |
|
752 | |||
751 | #----------------------------------------------------------------------------- |
|
753 | #----------------------------------------------------------------------------- | |
752 | # Prefilter handlers |
|
754 | # Prefilter handlers | |
753 | #----------------------------------------------------------------------------- |
|
755 | #----------------------------------------------------------------------------- | |
754 |
|
756 | |||
755 |
|
757 | |||
756 | class PrefilterHandler(Configurable): |
|
758 | class PrefilterHandler(Configurable): | |
757 |
|
759 | |||
758 | handler_name = Unicode('normal') |
|
760 | handler_name = Unicode('normal') | |
759 | esc_strings = List([]) |
|
761 | esc_strings = List([]) | |
760 | shell = Instance('IPython.core.interactiveshell.InteractiveShellABC') |
|
762 | shell = Instance('IPython.core.interactiveshell.InteractiveShellABC') | |
761 | prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager') |
|
763 | prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager') | |
762 |
|
764 | |||
763 | def __init__(self, shell=None, prefilter_manager=None, config=None): |
|
765 | def __init__(self, shell=None, prefilter_manager=None, config=None): | |
764 | super(PrefilterHandler, self).__init__( |
|
766 | super(PrefilterHandler, self).__init__( | |
765 | shell=shell, prefilter_manager=prefilter_manager, config=config |
|
767 | shell=shell, prefilter_manager=prefilter_manager, config=config | |
766 | ) |
|
768 | ) | |
767 | self.prefilter_manager.register_handler( |
|
769 | self.prefilter_manager.register_handler( | |
768 | self.handler_name, |
|
770 | self.handler_name, | |
769 | self, |
|
771 | self, | |
770 | self.esc_strings |
|
772 | self.esc_strings | |
771 | ) |
|
773 | ) | |
772 |
|
774 | |||
773 | def handle(self, line_info): |
|
775 | def handle(self, line_info): | |
774 | # print "normal: ", line_info |
|
776 | # print "normal: ", line_info | |
775 | """Handle normal input lines. Use as a template for handlers.""" |
|
777 | """Handle normal input lines. Use as a template for handlers.""" | |
776 |
|
778 | |||
777 | # With autoindent on, we need some way to exit the input loop, and I |
|
779 | # With autoindent on, we need some way to exit the input loop, and I | |
778 | # don't want to force the user to have to backspace all the way to |
|
780 | # don't want to force the user to have to backspace all the way to | |
779 | # clear the line. The rule will be in this case, that either two |
|
781 | # clear the line. The rule will be in this case, that either two | |
780 | # lines of pure whitespace in a row, or a line of pure whitespace but |
|
782 | # lines of pure whitespace in a row, or a line of pure whitespace but | |
781 | # of a size different to the indent level, will exit the input loop. |
|
783 | # of a size different to the indent level, will exit the input loop. | |
782 | line = line_info.line |
|
784 | line = line_info.line | |
783 | continue_prompt = line_info.continue_prompt |
|
785 | continue_prompt = line_info.continue_prompt | |
784 |
|
786 | |||
785 | if (continue_prompt and |
|
787 | if (continue_prompt and | |
786 | self.shell.autoindent and |
|
788 | self.shell.autoindent and | |
787 | line.isspace() and |
|
789 | line.isspace() and | |
788 | 0 < abs(len(line) - self.shell.indent_current_nsp) <= 2): |
|
790 | 0 < abs(len(line) - self.shell.indent_current_nsp) <= 2): | |
789 | line = '' |
|
791 | line = '' | |
790 |
|
792 | |||
791 | return line |
|
793 | return line | |
792 |
|
794 | |||
793 | def __str__(self): |
|
795 | def __str__(self): | |
794 | return "<%s(name=%s)>" % (self.__class__.__name__, self.handler_name) |
|
796 | return "<%s(name=%s)>" % (self.__class__.__name__, self.handler_name) | |
795 |
|
797 | |||
796 |
|
798 | |||
797 | class AliasHandler(PrefilterHandler): |
|
799 | class AliasHandler(PrefilterHandler): | |
798 |
|
800 | |||
799 | handler_name = Unicode('alias') |
|
801 | handler_name = Unicode('alias') | |
800 |
|
802 | |||
801 | def handle(self, line_info): |
|
803 | def handle(self, line_info): | |
802 | """Handle alias input lines. """ |
|
804 | """Handle alias input lines. """ | |
803 | transformed = self.shell.alias_manager.expand_aliases(line_info.ifun,line_info.the_rest) |
|
805 | transformed = self.shell.alias_manager.expand_aliases(line_info.ifun,line_info.the_rest) | |
804 | # pre is needed, because it carries the leading whitespace. Otherwise |
|
806 | # pre is needed, because it carries the leading whitespace. Otherwise | |
805 | # aliases won't work in indented sections. |
|
807 | # aliases won't work in indented sections. | |
806 | line_out = '%sget_ipython().system(%s)' % (line_info.pre_whitespace, |
|
808 | line_out = '%sget_ipython().system(%s)' % (line_info.pre_whitespace, | |
807 | make_quoted_expr(transformed)) |
|
809 | make_quoted_expr(transformed)) | |
808 |
|
810 | |||
809 | return line_out |
|
811 | return line_out | |
810 |
|
812 | |||
811 |
|
813 | |||
812 | class ShellEscapeHandler(PrefilterHandler): |
|
814 | class ShellEscapeHandler(PrefilterHandler): | |
813 |
|
815 | |||
814 | handler_name = Unicode('shell') |
|
816 | handler_name = Unicode('shell') | |
815 | esc_strings = List([ESC_SHELL, ESC_SH_CAP]) |
|
817 | esc_strings = List([ESC_SHELL, ESC_SH_CAP]) | |
816 |
|
818 | |||
817 | def handle(self, line_info): |
|
819 | def handle(self, line_info): | |
818 | """Execute the line in a shell, empty return value""" |
|
820 | """Execute the line in a shell, empty return value""" | |
819 | magic_handler = self.prefilter_manager.get_handler_by_name('magic') |
|
821 | magic_handler = self.prefilter_manager.get_handler_by_name('magic') | |
820 |
|
822 | |||
821 | line = line_info.line |
|
823 | line = line_info.line | |
822 | if line.lstrip().startswith(ESC_SH_CAP): |
|
824 | if line.lstrip().startswith(ESC_SH_CAP): | |
823 | # rewrite LineInfo's line, ifun and the_rest to properly hold the |
|
825 | # rewrite LineInfo's line, ifun and the_rest to properly hold the | |
824 | # call to %sx and the actual command to be executed, so |
|
826 | # call to %sx and the actual command to be executed, so | |
825 | # handle_magic can work correctly. Note that this works even if |
|
827 | # handle_magic can work correctly. Note that this works even if | |
826 | # the line is indented, so it handles multi_line_specials |
|
828 | # the line is indented, so it handles multi_line_specials | |
827 | # properly. |
|
829 | # properly. | |
828 | new_rest = line.lstrip()[2:] |
|
830 | new_rest = line.lstrip()[2:] | |
829 | line_info.line = '%ssx %s' % (ESC_MAGIC, new_rest) |
|
831 | line_info.line = '%ssx %s' % (ESC_MAGIC, new_rest) | |
830 | line_info.ifun = 'sx' |
|
832 | line_info.ifun = 'sx' | |
831 | line_info.the_rest = new_rest |
|
833 | line_info.the_rest = new_rest | |
832 | return magic_handler.handle(line_info) |
|
834 | return magic_handler.handle(line_info) | |
833 | else: |
|
835 | else: | |
834 | cmd = line.lstrip().lstrip(ESC_SHELL) |
|
836 | cmd = line.lstrip().lstrip(ESC_SHELL) | |
835 | line_out = '%sget_ipython().system(%s)' % (line_info.pre_whitespace, |
|
837 | line_out = '%sget_ipython().system(%s)' % (line_info.pre_whitespace, | |
836 | make_quoted_expr(cmd)) |
|
838 | make_quoted_expr(cmd)) | |
837 | return line_out |
|
839 | return line_out | |
838 |
|
840 | |||
839 |
|
841 | |||
840 | class MacroHandler(PrefilterHandler): |
|
842 | class MacroHandler(PrefilterHandler): | |
841 | handler_name = Unicode("macro") |
|
843 | handler_name = Unicode("macro") | |
842 |
|
844 | |||
843 | def handle(self, line_info): |
|
845 | def handle(self, line_info): | |
844 | obj = self.shell.user_ns.get(line_info.ifun) |
|
846 | obj = self.shell.user_ns.get(line_info.ifun) | |
845 | pre_space = line_info.pre_whitespace |
|
847 | pre_space = line_info.pre_whitespace | |
846 | line_sep = "\n" + pre_space |
|
848 | line_sep = "\n" + pre_space | |
847 | return pre_space + line_sep.join(obj.value.splitlines()) |
|
849 | return pre_space + line_sep.join(obj.value.splitlines()) | |
848 |
|
850 | |||
849 |
|
851 | |||
850 | class MagicHandler(PrefilterHandler): |
|
852 | class MagicHandler(PrefilterHandler): | |
851 |
|
853 | |||
852 | handler_name = Unicode('magic') |
|
854 | handler_name = Unicode('magic') | |
853 | esc_strings = List([ESC_MAGIC]) |
|
855 | esc_strings = List([ESC_MAGIC]) | |
854 |
|
856 | |||
855 | def handle(self, line_info): |
|
857 | def handle(self, line_info): | |
856 | """Execute magic functions.""" |
|
858 | """Execute magic functions.""" | |
857 | ifun = line_info.ifun |
|
859 | ifun = line_info.ifun | |
858 | the_rest = line_info.the_rest |
|
860 | the_rest = line_info.the_rest | |
859 | cmd = '%sget_ipython().magic(%s)' % (line_info.pre_whitespace, |
|
861 | cmd = '%sget_ipython().magic(%s)' % (line_info.pre_whitespace, | |
860 | make_quoted_expr(ifun + " " + the_rest)) |
|
862 | make_quoted_expr(ifun + " " + the_rest)) | |
861 | return cmd |
|
863 | return cmd | |
862 |
|
864 | |||
863 |
|
865 | |||
864 | class AutoHandler(PrefilterHandler): |
|
866 | class AutoHandler(PrefilterHandler): | |
865 |
|
867 | |||
866 | handler_name = Unicode('auto') |
|
868 | handler_name = Unicode('auto') | |
867 | esc_strings = List([ESC_PAREN, ESC_QUOTE, ESC_QUOTE2]) |
|
869 | esc_strings = List([ESC_PAREN, ESC_QUOTE, ESC_QUOTE2]) | |
868 |
|
870 | |||
869 | def handle(self, line_info): |
|
871 | def handle(self, line_info): | |
870 | """Handle lines which can be auto-executed, quoting if requested.""" |
|
872 | """Handle lines which can be auto-executed, quoting if requested.""" | |
871 | line = line_info.line |
|
873 | line = line_info.line | |
872 | ifun = line_info.ifun |
|
874 | ifun = line_info.ifun | |
873 | the_rest = line_info.the_rest |
|
875 | the_rest = line_info.the_rest | |
874 | pre = line_info.pre |
|
876 | pre = line_info.pre | |
|
877 | esc = line_info.esc | |||
875 | continue_prompt = line_info.continue_prompt |
|
878 | continue_prompt = line_info.continue_prompt | |
876 | obj = line_info.ofind(self)['obj'] |
|
879 | obj = line_info.ofind(self)['obj'] | |
877 | #print 'pre <%s> ifun <%s> rest <%s>' % (pre,ifun,the_rest) # dbg |
|
880 | #print 'pre <%s> ifun <%s> rest <%s>' % (pre,ifun,the_rest) # dbg | |
878 |
|
881 | |||
879 | # This should only be active for single-line input! |
|
882 | # This should only be active for single-line input! | |
880 | if continue_prompt: |
|
883 | if continue_prompt: | |
881 | return line |
|
884 | return line | |
882 |
|
885 | |||
883 | force_auto = isinstance(obj, IPyAutocall) |
|
886 | force_auto = isinstance(obj, IPyAutocall) | |
884 | auto_rewrite = getattr(obj, 'rewrite', True) |
|
887 | auto_rewrite = getattr(obj, 'rewrite', True) | |
885 |
|
888 | |||
886 |
if |
|
889 | if esc == ESC_QUOTE: | |
887 | # Auto-quote splitting on whitespace |
|
890 | # Auto-quote splitting on whitespace | |
888 | newcmd = '%s("%s")' % (ifun,'", "'.join(the_rest.split()) ) |
|
891 | newcmd = '%s("%s")' % (ifun,'", "'.join(the_rest.split()) ) | |
889 |
elif |
|
892 | elif esc == ESC_QUOTE2: | |
890 | # Auto-quote whole string |
|
893 | # Auto-quote whole string | |
891 | newcmd = '%s("%s")' % (ifun,the_rest) |
|
894 | newcmd = '%s("%s")' % (ifun,the_rest) | |
892 |
elif |
|
895 | elif esc == ESC_PAREN: | |
893 | newcmd = '%s(%s)' % (ifun,",".join(the_rest.split())) |
|
896 | newcmd = '%s(%s)' % (ifun,",".join(the_rest.split())) | |
894 | else: |
|
897 | else: | |
895 | # Auto-paren. |
|
898 | # Auto-paren. | |
896 | # We only apply it to argument-less calls if the autocall |
|
899 | # We only apply it to argument-less calls if the autocall | |
897 | # parameter is set to 2. We only need to check that autocall is < |
|
900 | # parameter is set to 2. We only need to check that autocall is < | |
898 | # 2, since this function isn't called unless it's at least 1. |
|
901 | # 2, since this function isn't called unless it's at least 1. | |
899 | if not the_rest and (self.shell.autocall < 2) and not force_auto: |
|
902 | if not the_rest and (self.shell.autocall < 2) and not force_auto: | |
900 | newcmd = '%s %s' % (ifun,the_rest) |
|
903 | newcmd = '%s %s' % (ifun,the_rest) | |
901 | auto_rewrite = False |
|
904 | auto_rewrite = False | |
902 | else: |
|
905 | else: | |
903 | if not force_auto and the_rest.startswith('['): |
|
906 | if not force_auto and the_rest.startswith('['): | |
904 | if hasattr(obj,'__getitem__'): |
|
907 | if hasattr(obj,'__getitem__'): | |
905 | # Don't autocall in this case: item access for an object |
|
908 | # Don't autocall in this case: item access for an object | |
906 | # which is BOTH callable and implements __getitem__. |
|
909 | # which is BOTH callable and implements __getitem__. | |
907 | newcmd = '%s %s' % (ifun,the_rest) |
|
910 | newcmd = '%s %s' % (ifun,the_rest) | |
908 | auto_rewrite = False |
|
911 | auto_rewrite = False | |
909 | else: |
|
912 | else: | |
910 | # if the object doesn't support [] access, go ahead and |
|
913 | # if the object doesn't support [] access, go ahead and | |
911 | # autocall |
|
914 | # autocall | |
912 | newcmd = '%s(%s)' % (ifun.rstrip(),the_rest) |
|
915 | newcmd = '%s(%s)' % (ifun.rstrip(),the_rest) | |
913 | elif the_rest.endswith(';'): |
|
916 | elif the_rest.endswith(';'): | |
914 | newcmd = '%s(%s);' % (ifun.rstrip(),the_rest[:-1]) |
|
917 | newcmd = '%s(%s);' % (ifun.rstrip(),the_rest[:-1]) | |
915 | else: |
|
918 | else: | |
916 | newcmd = '%s(%s)' % (ifun.rstrip(), the_rest) |
|
919 | newcmd = '%s(%s)' % (ifun.rstrip(), the_rest) | |
917 |
|
920 | |||
918 | if auto_rewrite: |
|
921 | if auto_rewrite: | |
919 | self.shell.auto_rewrite_input(newcmd) |
|
922 | self.shell.auto_rewrite_input(newcmd) | |
920 |
|
923 | |||
921 | return newcmd |
|
924 | return newcmd | |
922 |
|
925 | |||
923 |
|
926 | |||
924 | class HelpHandler(PrefilterHandler): |
|
927 | class HelpHandler(PrefilterHandler): | |
925 |
|
928 | |||
926 | handler_name = Unicode('help') |
|
929 | handler_name = Unicode('help') | |
927 | esc_strings = List([ESC_HELP]) |
|
930 | esc_strings = List([ESC_HELP]) | |
928 |
|
931 | |||
929 | def handle(self, line_info): |
|
932 | def handle(self, line_info): | |
930 | """Try to get some help for the object. |
|
933 | """Try to get some help for the object. | |
931 |
|
934 | |||
932 | obj? or ?obj -> basic information. |
|
935 | obj? or ?obj -> basic information. | |
933 | obj?? or ??obj -> more details. |
|
936 | obj?? or ??obj -> more details. | |
934 | """ |
|
937 | """ | |
935 | normal_handler = self.prefilter_manager.get_handler_by_name('normal') |
|
938 | normal_handler = self.prefilter_manager.get_handler_by_name('normal') | |
936 | line = line_info.line |
|
939 | line = line_info.line | |
937 | # We need to make sure that we don't process lines which would be |
|
940 | # We need to make sure that we don't process lines which would be | |
938 | # otherwise valid python, such as "x=1 # what?" |
|
941 | # otherwise valid python, such as "x=1 # what?" | |
939 | try: |
|
942 | try: | |
940 | codeop.compile_command(line) |
|
943 | codeop.compile_command(line) | |
941 | except SyntaxError: |
|
944 | except SyntaxError: | |
942 | # We should only handle as help stuff which is NOT valid syntax |
|
945 | # We should only handle as help stuff which is NOT valid syntax | |
943 | if line[0]==ESC_HELP: |
|
946 | if line[0]==ESC_HELP: | |
944 | line = line[1:] |
|
947 | line = line[1:] | |
945 | elif line[-1]==ESC_HELP: |
|
948 | elif line[-1]==ESC_HELP: | |
946 | line = line[:-1] |
|
949 | line = line[:-1] | |
947 | if line: |
|
950 | if line: | |
948 | #print 'line:<%r>' % line # dbg |
|
951 | #print 'line:<%r>' % line # dbg | |
949 | self.shell.magic_pinfo(line) |
|
952 | self.shell.magic_pinfo(line_info.ifun) | |
950 | else: |
|
953 | else: | |
951 | self.shell.show_usage() |
|
954 | self.shell.show_usage() | |
952 | return '' # Empty string is needed here! |
|
955 | return '' # Empty string is needed here! | |
953 | except: |
|
956 | except: | |
954 | raise |
|
957 | raise | |
955 | # Pass any other exceptions through to the normal handler |
|
958 | # Pass any other exceptions through to the normal handler | |
956 | return normal_handler.handle(line_info) |
|
959 | return normal_handler.handle(line_info) | |
957 | else: |
|
960 | else: | |
958 | # If the code compiles ok, we should handle it normally |
|
961 | # If the code compiles ok, we should handle it normally | |
959 | return normal_handler.handle(line_info) |
|
962 | return normal_handler.handle(line_info) | |
960 |
|
963 | |||
961 |
|
964 | |||
962 | class EmacsHandler(PrefilterHandler): |
|
965 | class EmacsHandler(PrefilterHandler): | |
963 |
|
966 | |||
964 | handler_name = Unicode('emacs') |
|
967 | handler_name = Unicode('emacs') | |
965 | esc_strings = List([]) |
|
968 | esc_strings = List([]) | |
966 |
|
969 | |||
967 | def handle(self, line_info): |
|
970 | def handle(self, line_info): | |
968 | """Handle input lines marked by python-mode.""" |
|
971 | """Handle input lines marked by python-mode.""" | |
969 |
|
972 | |||
970 | # Currently, nothing is done. Later more functionality can be added |
|
973 | # Currently, nothing is done. Later more functionality can be added | |
971 | # here if needed. |
|
974 | # here if needed. | |
972 |
|
975 | |||
973 | # The input cache shouldn't be updated |
|
976 | # The input cache shouldn't be updated | |
974 | return line_info.line |
|
977 | return line_info.line | |
975 |
|
978 | |||
976 |
|
979 | |||
977 | #----------------------------------------------------------------------------- |
|
980 | #----------------------------------------------------------------------------- | |
978 | # Defaults |
|
981 | # Defaults | |
979 | #----------------------------------------------------------------------------- |
|
982 | #----------------------------------------------------------------------------- | |
980 |
|
983 | |||
981 |
|
984 | |||
982 | _default_transformers = [ |
|
985 | _default_transformers = [ | |
983 | AssignSystemTransformer, |
|
986 | AssignSystemTransformer, | |
984 | AssignMagicTransformer, |
|
987 | AssignMagicTransformer, | |
985 | PyPromptTransformer, |
|
988 | PyPromptTransformer, | |
986 | IPyPromptTransformer, |
|
989 | IPyPromptTransformer, | |
987 | ] |
|
990 | ] | |
988 |
|
991 | |||
989 | _default_checkers = [ |
|
992 | _default_checkers = [ | |
990 | EmacsChecker, |
|
993 | EmacsChecker, | |
991 | ShellEscapeChecker, |
|
994 | ShellEscapeChecker, | |
992 | MacroChecker, |
|
995 | MacroChecker, | |
993 | IPyAutocallChecker, |
|
996 | IPyAutocallChecker, | |
994 | MultiLineMagicChecker, |
|
997 | MultiLineMagicChecker, | |
995 | EscCharsChecker, |
|
998 | EscCharsChecker, | |
996 | AssignmentChecker, |
|
999 | AssignmentChecker, | |
997 | AutoMagicChecker, |
|
1000 | AutoMagicChecker, | |
998 | AliasChecker, |
|
1001 | AliasChecker, | |
999 | PythonOpsChecker, |
|
1002 | PythonOpsChecker, | |
1000 | AutocallChecker |
|
1003 | AutocallChecker | |
1001 | ] |
|
1004 | ] | |
1002 |
|
1005 | |||
1003 | _default_handlers = [ |
|
1006 | _default_handlers = [ | |
1004 | PrefilterHandler, |
|
1007 | PrefilterHandler, | |
1005 | AliasHandler, |
|
1008 | AliasHandler, | |
1006 | ShellEscapeHandler, |
|
1009 | ShellEscapeHandler, | |
1007 | MacroHandler, |
|
1010 | MacroHandler, | |
1008 | MagicHandler, |
|
1011 | MagicHandler, | |
1009 | AutoHandler, |
|
1012 | AutoHandler, | |
1010 | HelpHandler, |
|
1013 | HelpHandler, | |
1011 | EmacsHandler |
|
1014 | EmacsHandler | |
1012 | ] |
|
1015 | ] |
@@ -1,89 +1,86 | |||||
1 | # encoding: utf-8 |
|
1 | # encoding: utf-8 | |
2 | """ |
|
2 | """ | |
3 | Simple utility for splitting user input. |
|
3 | Simple utility for splitting user input. | |
4 |
|
4 | |||
5 | Authors: |
|
5 | Authors: | |
6 |
|
6 | |||
7 | * Brian Granger |
|
7 | * Brian Granger | |
8 | * Fernando Perez |
|
8 | * Fernando Perez | |
9 | """ |
|
9 | """ | |
10 |
|
10 | |||
11 | #----------------------------------------------------------------------------- |
|
11 | #----------------------------------------------------------------------------- | |
12 | # Copyright (C) 2008-2009 The IPython Development Team |
|
12 | # Copyright (C) 2008-2009 The IPython Development Team | |
13 | # |
|
13 | # | |
14 | # Distributed under the terms of the BSD License. The full license is in |
|
14 | # Distributed under the terms of the BSD License. The full license is in | |
15 | # the file COPYING, distributed as part of this software. |
|
15 | # the file COPYING, distributed as part of this software. | |
16 | #----------------------------------------------------------------------------- |
|
16 | #----------------------------------------------------------------------------- | |
17 |
|
17 | |||
18 | #----------------------------------------------------------------------------- |
|
18 | #----------------------------------------------------------------------------- | |
19 | # Imports |
|
19 | # Imports | |
20 | #----------------------------------------------------------------------------- |
|
20 | #----------------------------------------------------------------------------- | |
21 |
|
21 | |||
22 | import re |
|
22 | import re | |
23 | import sys |
|
23 | import sys | |
24 |
|
24 | |||
25 | from IPython.utils import py3compat |
|
25 | from IPython.utils import py3compat | |
26 |
|
26 | |||
27 | #----------------------------------------------------------------------------- |
|
27 | #----------------------------------------------------------------------------- | |
28 | # Main function |
|
28 | # Main function | |
29 | #----------------------------------------------------------------------------- |
|
29 | #----------------------------------------------------------------------------- | |
30 |
|
30 | |||
31 |
|
31 | |||
32 | # RegExp for splitting line contents into pre-char//first word-method//rest. |
|
32 | # RegExp for splitting line contents into pre-char//first word-method//rest. | |
33 | # For clarity, each group in on one line. |
|
33 | # For clarity, each group in on one line. | |
34 |
|
34 | |||
35 | # WARNING: update the regexp if the escapes in interactiveshell are changed, as they |
|
35 | # WARNING: update the regexp if the escapes in interactiveshell are changed, as they | |
36 | # are hardwired in. |
|
36 | # are hardwired in. | |
37 |
|
37 | |||
38 | # Although it's not solely driven by the regex, note that: |
|
38 | # Although it's not solely driven by the regex, note that: | |
39 | # ,;/% only trigger if they are the first character on the line |
|
39 | # ,;/% only trigger if they are the first character on the line | |
40 | # ! and !! trigger if they are first char(s) *or* follow an indent |
|
40 | # ! and !! trigger if they are first char(s) *or* follow an indent | |
41 | # ? triggers as first or last char. |
|
41 | # ? triggers as first or last char. | |
42 |
|
42 | |||
43 |
# The |
|
43 | # The four parts of the regex are: | |
44 |
# 1) pre: |
|
44 | # 1) pre: initial whitespace | |
45 | # 2) ifun: first word/method (mix of \w and '.') |
|
45 | # 2) esc: escape character | |
46 | # 3) the_rest: rest of line (separated from ifun by space if non-empty) |
|
46 | # 3) ifun: first word/method (mix of \w and '.') | |
47 | line_split = re.compile(r'^([,;/%?]|!!?|\s*)' |
|
47 | # 4) the_rest: rest of line (separated from ifun by space if non-empty) | |
|
48 | line_split = re.compile(r'^(\s*)' | |||
|
49 | r'([,;/%?]|!!?)?' | |||
48 | r'\s*([\w\.]+)' |
|
50 | r'\s*([\w\.]+)' | |
49 |
r'( |
|
51 | r'(.*$|$)') | |
50 |
|
52 | |||
51 | # r'[\w\.]+' |
|
53 | # r'[\w\.]+' | |
52 | # r'\s*=\s*%.*' |
|
54 | # r'\s*=\s*%.*' | |
53 |
|
55 | |||
54 | def split_user_input(line, pattern=None): |
|
56 | def split_user_input(line, pattern=None): | |
55 | """Split user input into pre-char/whitespace, function part and rest. |
|
57 | """Split user input into pre-char/whitespace, function part and rest. | |
56 |
|
58 | |||
57 | This is currently handles lines with '=' in them in a very inconsistent |
|
59 | This is currently handles lines with '=' in them in a very inconsistent | |
58 | manner. |
|
60 | manner. | |
59 | """ |
|
61 | """ | |
60 | # We need to ensure that the rest of this routine deals only with unicode |
|
62 | # We need to ensure that the rest of this routine deals only with unicode | |
61 | line = py3compat.cast_unicode(line, sys.stdin.encoding or 'utf-8') |
|
63 | line = py3compat.cast_unicode(line, sys.stdin.encoding or 'utf-8') | |
62 |
|
64 | |||
63 | if pattern is None: |
|
65 | if pattern is None: | |
64 | pattern = line_split |
|
66 | pattern = line_split | |
65 | match = pattern.match(line) |
|
67 | match = pattern.match(line) | |
66 | if not match: |
|
68 | if not match: | |
67 | # print "match failed for line '%s'" % line |
|
69 | # print "match failed for line '%s'" % line | |
68 | try: |
|
70 | try: | |
69 | ifun, the_rest = line.split(None,1) |
|
71 | ifun, the_rest = line.split(None,1) | |
70 | except ValueError: |
|
72 | except ValueError: | |
71 | # print "split failed for line '%s'" % line |
|
73 | # print "split failed for line '%s'" % line | |
72 | ifun, the_rest = line, u'' |
|
74 | ifun, the_rest = line, u'' | |
73 | pre = re.match('^(\s*)(.*)',line).groups()[0] |
|
75 | pre = re.match('^(\s*)(.*)',line).groups()[0] | |
|
76 | esc = "" | |||
74 | else: |
|
77 | else: | |
75 | pre,ifun,the_rest = match.groups() |
|
78 | pre, esc, ifun, the_rest = match.groups() | |
76 |
|
79 | |||
77 | if not py3compat.PY3: |
|
80 | if not py3compat.isidentifier(ifun, dotted=True): | |
78 | # ifun has to be a valid python identifier, so it better encode into |
|
|||
79 | # ascii. We do still make it a unicode string so that we consistently |
|
|||
80 | # return unicode, but it will be one that is guaranteed to be pure ascii |
|
|||
81 | try: |
|
|||
82 | ifun = unicode(ifun.encode('ascii')) |
|
|||
83 | except UnicodeEncodeError: |
|
|||
84 |
|
|
81 | the_rest = ifun + u' ' + the_rest | |
85 |
|
|
82 | ifun = u'' | |
86 |
|
83 | |||
87 | #print 'line:<%s>' % line # dbg |
|
84 | #print 'line:<%s>' % line # dbg | |
88 | #print 'pre <%s> ifun <%s> rest <%s>' % (pre,ifun.strip(),the_rest) # dbg |
|
85 | #print 'pre <%s> ifun <%s> rest <%s>' % (pre,ifun.strip(),the_rest) # dbg | |
89 | return pre, ifun.strip(), the_rest.lstrip() |
|
86 | return pre, esc, ifun.strip(), the_rest.lstrip() |
@@ -1,172 +1,165 | |||||
1 | """Tests for input handlers. |
|
1 | """Tests for input handlers. | |
2 | """ |
|
2 | """ | |
3 | #----------------------------------------------------------------------------- |
|
3 | #----------------------------------------------------------------------------- | |
4 | # Module imports |
|
4 | # Module imports | |
5 | #----------------------------------------------------------------------------- |
|
5 | #----------------------------------------------------------------------------- | |
6 |
|
6 | |||
7 | # third party |
|
7 | # third party | |
8 | import nose.tools as nt |
|
8 | import nose.tools as nt | |
9 |
|
9 | |||
10 | # our own packages |
|
10 | # our own packages | |
11 | from IPython.core import autocall |
|
11 | from IPython.core import autocall | |
12 | from IPython.testing import decorators as dec |
|
12 | from IPython.testing import decorators as dec | |
|
13 | from IPython.testing import tools as tt | |||
13 | from IPython.testing.globalipapp import get_ipython |
|
14 | from IPython.testing.globalipapp import get_ipython | |
14 |
|
15 | |||
15 | #----------------------------------------------------------------------------- |
|
16 | #----------------------------------------------------------------------------- | |
16 | # Globals |
|
17 | # Globals | |
17 | #----------------------------------------------------------------------------- |
|
18 | #----------------------------------------------------------------------------- | |
18 |
|
19 | |||
19 | # Get the public instance of IPython |
|
20 | # Get the public instance of IPython | |
20 | ip = get_ipython() |
|
21 | ip = get_ipython() | |
21 |
|
22 | |||
22 | failures = [] |
|
23 | failures = [] | |
23 | num_tests = 0 |
|
24 | num_tests = 0 | |
24 |
|
25 | |||
25 | #----------------------------------------------------------------------------- |
|
26 | #----------------------------------------------------------------------------- | |
26 | # Test functions |
|
27 | # Test functions | |
27 | #----------------------------------------------------------------------------- |
|
28 | #----------------------------------------------------------------------------- | |
28 |
|
29 | |||
29 | class CallableIndexable(object): |
|
30 | class CallableIndexable(object): | |
30 | def __getitem__(self, idx): return True |
|
31 | def __getitem__(self, idx): return True | |
31 | def __call__(self, *args, **kws): return True |
|
32 | def __call__(self, *args, **kws): return True | |
32 |
|
33 | |||
33 |
|
34 | |||
34 | class Autocallable(autocall.IPyAutocall): |
|
35 | class Autocallable(autocall.IPyAutocall): | |
35 | def __call__(self): |
|
36 | def __call__(self): | |
36 | return "called" |
|
37 | return "called" | |
37 |
|
38 | |||
38 |
|
39 | |||
39 | def run(tests): |
|
40 | def run(tests): | |
40 | """Loop through a list of (pre, post) inputs, where pre is the string |
|
41 | """Loop through a list of (pre, post) inputs, where pre is the string | |
41 | handed to ipython, and post is how that string looks after it's been |
|
42 | handed to ipython, and post is how that string looks after it's been | |
42 | transformed (i.e. ipython's notion of _i)""" |
|
43 | transformed (i.e. ipython's notion of _i)""" | |
43 | for pre, post in tests: |
|
44 | tt.check_pairs(ip.prefilter_manager.prefilter_lines, tests) | |
44 | global num_tests |
|
|||
45 | num_tests += 1 |
|
|||
46 | actual = ip.prefilter_manager.prefilter_lines(pre) |
|
|||
47 | if actual != None: |
|
|||
48 | actual = actual.rstrip('\n') |
|
|||
49 | if actual != post: |
|
|||
50 | failures.append('Expected %r to become %r, found %r' % ( |
|
|||
51 | pre, post, actual)) |
|
|||
52 |
|
45 | |||
53 |
|
46 | |||
54 | def test_handlers(): |
|
47 | def test_handlers(): | |
55 | # alias expansion |
|
48 | # alias expansion | |
56 |
|
49 | |||
57 | # We're using 'true' as our syscall of choice because it doesn't |
|
50 | # We're using 'true' as our syscall of choice because it doesn't | |
58 | # write anything to stdout. |
|
51 | # write anything to stdout. | |
59 |
|
52 | |||
60 | # Turn off actual execution of aliases, because it's noisy |
|
53 | # Turn off actual execution of aliases, because it's noisy | |
61 | old_system_cmd = ip.system |
|
54 | old_system_cmd = ip.system | |
62 | ip.system = lambda cmd: None |
|
55 | ip.system = lambda cmd: None | |
63 |
|
56 | |||
64 |
|
57 | |||
65 | ip.alias_manager.alias_table['an_alias'] = (0, 'true') |
|
58 | ip.alias_manager.alias_table['an_alias'] = (0, 'true') | |
66 | # These are useful for checking a particular recursive alias issue |
|
59 | # These are useful for checking a particular recursive alias issue | |
67 | ip.alias_manager.alias_table['top'] = (0, 'd:/cygwin/top') |
|
60 | ip.alias_manager.alias_table['top'] = (0, 'd:/cygwin/top') | |
68 | ip.alias_manager.alias_table['d'] = (0, 'true') |
|
61 | ip.alias_manager.alias_table['d'] = (0, 'true') | |
69 | run([("an_alias", 'get_ipython().system(u"true ")'), # alias |
|
62 | run([("an_alias", 'get_ipython().system(u"true ")'), # alias | |
70 | # Below: recursive aliases should expand whitespace-surrounded |
|
63 | # Below: recursive aliases should expand whitespace-surrounded | |
71 | # chars, *not* initial chars which happen to be aliases: |
|
64 | # chars, *not* initial chars which happen to be aliases: | |
72 | ("top", 'get_ipython().system(u"d:/cygwin/top ")'), |
|
65 | ("top", 'get_ipython().system(u"d:/cygwin/top ")'), | |
73 | ]) |
|
66 | ]) | |
74 | ip.system = old_system_cmd |
|
67 | ip.system = old_system_cmd | |
75 |
|
68 | |||
76 | call_idx = CallableIndexable() |
|
69 | call_idx = CallableIndexable() | |
77 | ip.user_ns['call_idx'] = call_idx |
|
70 | ip.user_ns['call_idx'] = call_idx | |
78 |
|
71 | |||
79 | # For many of the below, we're also checking that leading whitespace |
|
72 | # For many of the below, we're also checking that leading whitespace | |
80 | # turns off the esc char, which it should unless there is a continuation |
|
73 | # turns off the esc char, which it should unless there is a continuation | |
81 | # line. |
|
74 | # line. | |
82 | run([('"no change"', '"no change"'), # normal |
|
75 | run([('"no change"', '"no change"'), # normal | |
83 | ("!true", 'get_ipython().system(u"true")'), # shell_escapes |
|
76 | ("!true", 'get_ipython().system(u"true")'), # shell_escapes | |
84 | ("!! true", 'get_ipython().magic(u"sx true")'), # shell_escapes + magic |
|
77 | ("!! true", 'get_ipython().magic(u"sx true")'), # shell_escapes + magic | |
85 | ("!!true", 'get_ipython().magic(u"sx true")'), # shell_escapes + magic |
|
78 | ("!!true", 'get_ipython().magic(u"sx true")'), # shell_escapes + magic | |
86 | ("%lsmagic", 'get_ipython().magic(u"lsmagic ")'), # magic |
|
79 | ("%lsmagic", 'get_ipython().magic(u"lsmagic ")'), # magic | |
87 | ("lsmagic", 'get_ipython().magic(u"lsmagic ")'), # magic |
|
80 | ("lsmagic", 'get_ipython().magic(u"lsmagic ")'), # magic | |
88 | #("a = b # PYTHON-MODE", '_i'), # emacs -- avoids _in cache |
|
81 | #("a = b # PYTHON-MODE", '_i'), # emacs -- avoids _in cache | |
89 |
|
82 | |||
90 | # post-esc-char whitespace goes inside |
|
83 | # post-esc-char whitespace goes inside | |
91 | ("! true", 'get_ipython().system(u" true")'), |
|
84 | ("! true", 'get_ipython().system(u" true")'), | |
92 |
|
85 | |||
93 | # handle_help |
|
86 | # handle_help | |
94 |
|
87 | |||
95 | # These are weak tests -- just looking at what the help handlers |
|
88 | # These are weak tests -- just looking at what the help handlers | |
96 | # logs, which is not how it really does its work. But it still |
|
89 | # logs, which is not how it really does its work. But it still | |
97 | # lets us check the key paths through the handler. |
|
90 | # lets us check the key paths through the handler. | |
98 |
|
91 | |||
99 | ("x=1 # what?", "x=1 # what?"), # no help if valid python |
|
92 | ("x=1 # what?", "x=1 # what?"), # no help if valid python | |
100 | ]) |
|
93 | ]) | |
101 |
|
94 | |||
102 | # multi_line_specials |
|
95 | # multi_line_specials | |
103 | ip.prefilter_manager.multi_line_specials = False |
|
96 | ip.prefilter_manager.multi_line_specials = False | |
104 | # W/ multi_line_specials off, leading ws kills esc chars/autoexpansion |
|
97 | # W/ multi_line_specials off, leading ws kills esc chars/autoexpansion | |
105 | run([ |
|
98 | run([ | |
106 | ('if 1:\n !true', 'if 1:\n !true'), |
|
99 | ('if 1:\n !true', 'if 1:\n !true'), | |
107 | ('if 1:\n lsmagic', 'if 1:\n lsmagic'), |
|
100 | ('if 1:\n lsmagic', 'if 1:\n lsmagic'), | |
108 | ('if 1:\n an_alias', 'if 1:\n an_alias'), |
|
101 | ('if 1:\n an_alias', 'if 1:\n an_alias'), | |
109 | ]) |
|
102 | ]) | |
110 |
|
103 | |||
111 | ip.prefilter_manager.multi_line_specials = True |
|
104 | ip.prefilter_manager.multi_line_specials = True | |
112 | # initial indents must be preserved. |
|
105 | # initial indents must be preserved. | |
113 | run([ |
|
106 | run([ | |
114 | ('if 1:\n !true', 'if 1:\n get_ipython().system(u"true")'), |
|
107 | ('if 1:\n !true', 'if 1:\n get_ipython().system(u"true")'), | |
115 | ('if 2:\n lsmagic', 'if 2:\n get_ipython().magic(u"lsmagic ")'), |
|
108 | ('if 2:\n lsmagic', 'if 2:\n get_ipython().magic(u"lsmagic ")'), | |
116 | ('if 1:\n an_alias', 'if 1:\n get_ipython().system(u"true ")'), |
|
109 | ('if 1:\n an_alias', 'if 1:\n get_ipython().system(u"true ")'), | |
117 | # Weird one |
|
110 | # Weird one | |
118 | ('if 1:\n !!true', 'if 1:\n get_ipython().magic(u"sx true")'), |
|
111 | ('if 1:\n !!true', 'if 1:\n get_ipython().magic(u"sx true")'), | |
119 |
|
112 | |||
120 | # Even with m_l_s on, autocall is off even with special chars |
|
113 | # Even with m_l_s on, autocall is off even with special chars | |
121 | ('if 1:\n /fun 1 2', 'if 1:\n /fun 1 2'), |
|
114 | ('if 1:\n /fun 1 2', 'if 1:\n /fun 1 2'), | |
122 | ('if 1:\n ;fun 1 2', 'if 1:\n ;fun 1 2'), |
|
115 | ('if 1:\n ;fun 1 2', 'if 1:\n ;fun 1 2'), | |
123 | ('if 1:\n ,fun 1 2', 'if 1:\n ,fun 1 2'), |
|
116 | ('if 1:\n ,fun 1 2', 'if 1:\n ,fun 1 2'), | |
124 | ('if 1:\n ?fun 1 2', 'if 1:\n ?fun 1 2'), |
|
117 | ('if 1:\n ?fun 1 2', 'if 1:\n ?fun 1 2'), | |
125 | # What about !! |
|
118 | # What about !! | |
126 | ]) |
|
119 | ]) | |
127 |
|
120 | |||
128 | # Objects which are instances of IPyAutocall are *always* autocalled |
|
121 | # Objects which are instances of IPyAutocall are *always* autocalled | |
129 | autocallable = Autocallable() |
|
122 | autocallable = Autocallable() | |
130 | ip.user_ns['autocallable'] = autocallable |
|
123 | ip.user_ns['autocallable'] = autocallable | |
131 |
|
124 | |||
132 | # auto |
|
125 | # auto | |
133 | ip.magic('autocall 0') |
|
126 | ip.magic('autocall 0') | |
134 | # Only explicit escapes or instances of IPyAutocallable should get |
|
127 | # Only explicit escapes or instances of IPyAutocallable should get | |
135 | # expanded |
|
128 | # expanded | |
136 | run([ |
|
129 | run([ | |
137 | ('len "abc"', 'len "abc"'), |
|
130 | ('len "abc"', 'len "abc"'), | |
138 | ('autocallable', 'autocallable()'), |
|
131 | ('autocallable', 'autocallable()'), | |
139 | (",list 1 2 3", 'list("1", "2", "3")'), |
|
132 | (",list 1 2 3", 'list("1", "2", "3")'), | |
140 | (";list 1 2 3", 'list("1 2 3")'), |
|
133 | (";list 1 2 3", 'list("1 2 3")'), | |
141 | ("/len range(1,4)", 'len(range(1,4))'), |
|
134 | ("/len range(1,4)", 'len(range(1,4))'), | |
142 | ]) |
|
135 | ]) | |
143 | ip.magic('autocall 1') |
|
136 | ip.magic('autocall 1') | |
144 | run([ |
|
137 | run([ | |
145 | (",list 1 2 3", 'list("1", "2", "3")'), |
|
138 | (",list 1 2 3", 'list("1", "2", "3")'), | |
146 | (";list 1 2 3", 'list("1 2 3")'), |
|
139 | (";list 1 2 3", 'list("1 2 3")'), | |
147 | ("/len range(1,4)", 'len(range(1,4))'), |
|
140 | ("/len range(1,4)", 'len(range(1,4))'), | |
148 | ('len "abc"', 'len("abc")'), |
|
141 | ('len "abc"', 'len("abc")'), | |
149 | ('len "abc";', 'len("abc");'), # ; is special -- moves out of parens |
|
142 | ('len "abc";', 'len("abc");'), # ; is special -- moves out of parens | |
150 | # Autocall is turned off if first arg is [] and the object |
|
143 | # Autocall is turned off if first arg is [] and the object | |
151 | # is both callable and indexable. Like so: |
|
144 | # is both callable and indexable. Like so: | |
152 | ('len [1,2]', 'len([1,2])'), # len doesn't support __getitem__... |
|
145 | ('len [1,2]', 'len([1,2])'), # len doesn't support __getitem__... | |
153 | ('call_idx [1]', 'call_idx [1]'), # call_idx *does*.. |
|
146 | ('call_idx [1]', 'call_idx [1]'), # call_idx *does*.. | |
154 | ('call_idx 1', 'call_idx(1)'), |
|
147 | ('call_idx 1', 'call_idx(1)'), | |
155 | ('len', 'len '), # only at 2 does it auto-call on single args |
|
148 | ('len', 'len '), # only at 2 does it auto-call on single args | |
156 | ]) |
|
149 | ]) | |
157 | ip.magic('autocall 2') |
|
150 | ip.magic('autocall 2') | |
158 | run([ |
|
151 | run([ | |
159 | (",list 1 2 3", 'list("1", "2", "3")'), |
|
152 | (",list 1 2 3", 'list("1", "2", "3")'), | |
160 | (";list 1 2 3", 'list("1 2 3")'), |
|
153 | (";list 1 2 3", 'list("1 2 3")'), | |
161 | ("/len range(1,4)", 'len(range(1,4))'), |
|
154 | ("/len range(1,4)", 'len(range(1,4))'), | |
162 | ('len "abc"', 'len("abc")'), |
|
155 | ('len "abc"', 'len("abc")'), | |
163 | ('len "abc";', 'len("abc");'), |
|
156 | ('len "abc";', 'len("abc");'), | |
164 | ('len [1,2]', 'len([1,2])'), |
|
157 | ('len [1,2]', 'len([1,2])'), | |
165 | ('call_idx [1]', 'call_idx [1]'), |
|
158 | ('call_idx [1]', 'call_idx [1]'), | |
166 | ('call_idx 1', 'call_idx(1)'), |
|
159 | ('call_idx 1', 'call_idx(1)'), | |
167 | # This is what's different: |
|
160 | # This is what's different: | |
168 | ('len', 'len()'), # only at 2 does it auto-call on single args |
|
161 | ('len', 'len()'), # only at 2 does it auto-call on single args | |
169 | ]) |
|
162 | ]) | |
170 | ip.magic('autocall 1') |
|
163 | ip.magic('autocall 1') | |
171 |
|
164 | |||
172 | nt.assert_equals(failures, []) |
|
165 | nt.assert_equals(failures, []) |
General Comments 0
You need to be logged in to leave comments.
Login now