##// END OF EJS Templates
More work on refactoring things into components....
Brian Granger -
Show More
@@ -0,0 +1,77 b''
1 #!/usr/bin/env python
2 # encoding: utf-8
3 """
4 Simple utility for splitting user input.
5
6 Authors:
7
8 * Brian Granger
9 * Fernando Perez
10 """
11
12 #-----------------------------------------------------------------------------
13 # Copyright (C) 2008-2009 The IPython Development Team
14 #
15 # Distributed under the terms of the BSD License. The full license is in
16 # the file COPYING, distributed as part of this software.
17 #-----------------------------------------------------------------------------
18
19 #-----------------------------------------------------------------------------
20 # Imports
21 #-----------------------------------------------------------------------------
22
23 import re
24
25 #-----------------------------------------------------------------------------
26 # Main function
27 #-----------------------------------------------------------------------------
28
29
30 # RegExp for splitting line contents into pre-char//first word-method//rest.
31 # For clarity, each group in on one line.
32
33 # WARNING: update the regexp if the escapes in iplib are changed, as they
34 # are hardwired in.
35
36 # Although it's not solely driven by the regex, note that:
37 # ,;/% only trigger if they are the first character on the line
38 # ! and !! trigger if they are first char(s) *or* follow an indent
39 # ? triggers as first or last char.
40
41 # The three parts of the regex are:
42 # 1) pre: pre_char *or* initial whitespace
43 # 2) ifun: first word/method (mix of \w and '.')
44 # 3) the_rest: rest of line (separated from ifun by space if non-empty)
45 line_split = re.compile(r'^([,;/%?]|!!?|\s*)'
46 r'\s*([\w\.]+)'
47 r'(\s+.*$|$)')
48
49
50 def split_user_input(line, pattern=None):
51 """Split user input into pre-char/whitespace, function part and rest."""
52
53 if pattern is None:
54 pattern = line_split
55 match = pattern.match(line)
56 if not match:
57 #print "match failed for line '%s'" % line
58 try:
59 ifun, the_rest = line.split(None,1)
60 except ValueError:
61 #print "split failed for line '%s'" % line
62 ifun, the_rest = line,''
63 pre = re.match('^(\s*)(.*)',line).groups()[0]
64 else:
65 pre,ifun,the_rest = match.groups()
66
67 # ifun has to be a valid python identifier, so it better be only pure
68 # ascii, no unicode:
69 try:
70 ifun = ifun.encode('ascii')
71 except UnicodeEncodeError:
72 the_rest = ifun + u' ' + the_rest
73 ifun = u''
74
75 #print 'line:<%s>' % line # dbg
76 #print 'pre <%s> ifun <%s> rest <%s>' % (pre,ifun.strip(),the_rest) # dbg
77 return pre, ifun.strip(), the_rest.lstrip()
@@ -0,0 +1,162 b''
1 #!/usr/bin/env python
2 # encoding: utf-8
3 """Descriptor support for NIPY.
4
5 Utilities to support special Python descriptors [1,2], in particular the use of
6 a useful pattern for properties we call 'one time properties'. These are
7 object attributes which are declared as properties, but become regular
8 attributes once they've been read the first time. They can thus be evaluated
9 later in the object's life cycle, but once evaluated they become normal, static
10 attributes with no function call overhead on access or any other constraints.
11
12 A special ResetMixin class is provided to add a .reset() method to users who
13 may want to have their objects capable of resetting these computed properties
14 to their 'untriggered' state.
15
16 References
17 ----------
18 [1] How-To Guide for Descriptors, Raymond
19 Hettinger. http://users.rcn.com/python/download/Descriptor.htm
20
21 [2] Python data model, http://docs.python.org/reference/datamodel.html
22
23 Notes
24 -----
25 This module is taken from the NiPy project
26 (http://neuroimaging.scipy.org/site/index.html), and is BSD licensed.
27 """
28
29 #-----------------------------------------------------------------------------
30 # Classes and Functions
31 #-----------------------------------------------------------------------------
32
33 class ResetMixin(object):
34 """A Mixin class to add a .reset() method to users of OneTimeProperty.
35
36 By default, auto attributes once computed, become static. If they happen to
37 depend on other parts of an object and those parts change, their values may
38 now be invalid.
39
40 This class offers a .reset() method that users can call *explicitly* when
41 they know the state of their objects may have changed and they want to
42 ensure that *all* their special attributes should be invalidated. Once
43 reset() is called, all their auto attributes are reset to their
44 OneTimeProperty descriptors, and their accessor functions will be triggered
45 again.
46
47 Example
48 -------
49
50 >>> class A(ResetMixin):
51 ... def __init__(self,x=1.0):
52 ... self.x = x
53 ...
54 ... @auto_attr
55 ... def y(self):
56 ... print '*** y computation executed ***'
57 ... return self.x / 2.0
58 ...
59
60 >>> a = A(10)
61
62 About to access y twice, the second time no computation is done:
63 >>> a.y
64 *** y computation executed ***
65 5.0
66 >>> a.y
67 5.0
68
69 Changing x
70 >>> a.x = 20
71
72 a.y doesn't change to 10, since it is a static attribute:
73 >>> a.y
74 5.0
75
76 We now reset a, and this will then force all auto attributes to recompute
77 the next time we access them:
78 >>> a.reset()
79
80 About to access y twice again after reset():
81 >>> a.y
82 *** y computation executed ***
83 10.0
84 >>> a.y
85 10.0
86 """
87
88 def reset(self):
89 """Reset all OneTimeProperty attributes that may have fired already."""
90 instdict = self.__dict__
91 classdict = self.__class__.__dict__
92 # To reset them, we simply remove them from the instance dict. At that
93 # point, it's as if they had never been computed. On the next access,
94 # the accessor function from the parent class will be called, simply
95 # because that's how the python descriptor protocol works.
96 for mname, mval in classdict.items():
97 if mname in instdict and isinstance(mval, OneTimeProperty):
98 delattr(self, mname)
99
100
101 class OneTimeProperty(object):
102 """A descriptor to make special properties that become normal attributes.
103
104 This is meant to be used mostly by the auto_attr decorator in this module.
105 """
106 def __init__(self,func):
107 """Create a OneTimeProperty instance.
108
109 Parameters
110 ----------
111 func : method
112
113 The method that will be called the first time to compute a value.
114 Afterwards, the method's name will be a standard attribute holding
115 the value of this computation.
116 """
117 self.getter = func
118 self.name = func.func_name
119
120 def __get__(self,obj,type=None):
121 """This will be called on attribute access on the class or instance. """
122
123 if obj is None:
124 # Being called on the class, return the original function. This way,
125 # introspection works on the class.
126 #return func
127 return self.getter
128
129 val = self.getter(obj)
130 #print "** auto_attr - loading '%s'" % self.name # dbg
131 setattr(obj, self.name, val)
132 return val
133
134
135 def auto_attr(func):
136 """Decorator to create OneTimeProperty attributes.
137
138 Parameters
139 ----------
140 func : method
141 The method that will be called the first time to compute a value.
142 Afterwards, the method's name will be a standard attribute holding the
143 value of this computation.
144
145 Examples
146 --------
147 >>> class MagicProp(object):
148 ... @auto_attr
149 ... def a(self):
150 ... return 99
151 ...
152 >>> x = MagicProp()
153 >>> 'a' in x.__dict__
154 False
155 >>> x.a
156 99
157 >>> 'a' in x.__dict__
158 True
159 """
160 return OneTimeProperty(func)
161
162
@@ -22,17 +22,23 b' Authors:'
22 22 import __builtin__
23 23 import keyword
24 24 import os
25 import re
25 26 import sys
26 27
27 28 from IPython.core.component import Component
29 from IPython.core.splitinput import split_user_input
28 30
29 31 from IPython.utils.traitlets import CBool, List, Instance
30 32 from IPython.utils.genutils import error
33 from IPython.utils.autoattr import auto_attr
31 34
32 35 #-----------------------------------------------------------------------------
33 # Functions and classes
36 # Utilities
34 37 #-----------------------------------------------------------------------------
35 38
39 # This is used as the pattern for calls to split_user_input.
40 shell_line_split = re.compile(r'^(\s*)(\S*\s*)(.*$)')
41
36 42 def default_aliases():
37 43 # Make some aliases automatically
38 44 # Prepare list of shell aliases to auto-define
@@ -88,6 +94,11 b' class InvalidAliasError(AliasError):'
88 94 pass
89 95
90 96
97 #-----------------------------------------------------------------------------
98 # Main AliasManager class
99 #-----------------------------------------------------------------------------
100
101
91 102 class AliasManager(Component):
92 103
93 104 auto_alias = List(default_aliases())
@@ -95,14 +106,18 b' class AliasManager(Component):'
95 106
96 107 def __init__(self, parent, config=None):
97 108 super(AliasManager, self).__init__(parent, config=config)
98 self.shell = Component.get_instances(
99 root=self.root,
100 klass='IPython.core.iplib.InteractiveShell'
101 )[0]
102 109 self.alias_table = {}
103 110 self.exclude_aliases()
104 111 self.init_aliases()
105 112
113 @auto_attr
114 def shell(self):
115 shell = Component.get_instances(
116 root=self.root,
117 klass='IPython.core.iplib.InteractiveShell'
118 )[0]
119 return shell
120
106 121 def __contains__(self, name):
107 122 if name in self.alias_table:
108 123 return True
@@ -189,3 +204,54 b' class AliasManager(Component):'
189 204 (alias, nargs, len(args)))
190 205 cmd = '%s %s' % (cmd % tuple(args[:nargs]),' '.join(args[nargs:]))
191 206 return cmd
207
208 def expand_alias(self, line):
209 """ Expand an alias in the command line
210
211 Returns the provided command line, possibly with the first word
212 (command) translated according to alias expansion rules.
213
214 [ipython]|16> _ip.expand_aliases("np myfile.txt")
215 <16> 'q:/opt/np/notepad++.exe myfile.txt'
216 """
217
218 pre,fn,rest = split_user_input(line)
219 res = pre + self.expand_aliases(fn, rest)
220 return res
221
222 def expand_aliases(self, fn, rest):
223 """Expand multiple levels of aliases:
224
225 if:
226
227 alias foo bar /tmp
228 alias baz foo
229
230 then:
231
232 baz huhhahhei -> bar /tmp huhhahhei
233
234 """
235 line = fn + " " + rest
236
237 done = set()
238 while 1:
239 pre,fn,rest = split_user_input(line, shell_line_split)
240 if fn in self.alias_table:
241 if fn in done:
242 warn("Cyclic alias definition, repeated '%s'" % fn)
243 return ""
244 done.add(fn)
245
246 l2 = self.transform_alias(fn, rest)
247 if l2 == line:
248 break
249 # ls -> ls -F should not recurse forever
250 if l2.split(None,1)[0] == line.split(None,1)[0]:
251 line = l2
252 break
253 line=l2
254 else:
255 break
256
257 return line
@@ -24,7 +24,7 b' import __builtin__'
24 24 from IPython.core.component import Component
25 25 from IPython.core.quitter import Quitter
26 26
27 from IPython.utils.traitlets import Instance
27 from IPython.utils.autoattr import auto_attr
28 28
29 29 #-----------------------------------------------------------------------------
30 30 # Classes and functions
@@ -39,12 +39,15 b' class BuiltinTrap(Component):'
39 39
40 40 def __init__(self, parent):
41 41 super(BuiltinTrap, self).__init__(parent, None, None)
42 # Don't just grab parent!!!
43 self.shell = Component.get_instances(
42 self._orig_builtins = {}
43
44 @auto_attr
45 def shell(self):
46 shell = Component.get_instances(
44 47 root=self.root,
45 48 klass='IPython.core.iplib.InteractiveShell'
46 49 )[0]
47 self._orig_builtins = {}
50 return shell
48 51
49 52 def __enter__(self):
50 53 self.set()
@@ -74,7 +74,9 b' import itertools'
74 74 import types
75 75
76 76 from IPython.core.error import TryNext
77 import IPython.utils.rlineimpl as readline
77 from IPython.core.prefilter import ESC_MAGIC
78
79 import IPython.utils.rlineimpl as readline
78 80 from IPython.utils.ipstruct import Struct
79 81 from IPython.utils import generics
80 82
@@ -234,7 +236,7 b' class IPCompleter(Completer):'
234 236
235 237 Completer.__init__(self,namespace,global_namespace)
236 238 self.magic_prefix = shell.name+'.magic_'
237 self.magic_escape = shell.ESC_MAGIC
239 self.magic_escape = ESC_MAGIC
238 240 self.readline = readline
239 241 delims = self.readline.get_completer_delims()
240 242 delims = delims.replace(self.magic_escape,'')
@@ -301,5 +301,4 b' class Component(HasTraitlets):'
301 301 self._children.append(child)
302 302
303 303 def __repr__(self):
304 return "<%s('%s')>" % (self.__class__.__name__, "DummyName")
305 # return "<Component('%s')>" % self.name
304 return "<%s('%s')>" % (self.__class__.__name__, self.name)
@@ -24,6 +24,8 b' import sys'
24 24
25 25 from IPython.core.component import Component
26 26
27 from IPython.utils.autoattr import auto_attr
28
27 29 #-----------------------------------------------------------------------------
28 30 # Classes and functions
29 31 #-----------------------------------------------------------------------------
@@ -42,6 +44,14 b' class DisplayTrap(Component):'
42 44 self.hook = hook
43 45 self.old_hook = None
44 46
47 @auto_attr
48 def shell(self):
49 shell = Component.get_instances(
50 root=self.root,
51 klass='IPython.core.iplib.InteractiveShell'
52 )[0]
53 return shell
54
45 55 def __enter__(self):
46 56 self.set()
47 57 return self
@@ -49,10 +49,12 b' from IPython.core.logger import Logger'
49 49 from IPython.core.magic import Magic
50 50 from IPython.core.prompts import CachedOutput
51 51 from IPython.core.page import page
52 from IPython.core.prefilter import PrefilterManager
52 53 from IPython.core.component import Component
53 54 from IPython.core.oldusersetup import user_setup
54 55 from IPython.core.usage import interactive_usage, default_banner
55 56 from IPython.core.error import TryNext, UsageError
57 from IPython.core.splitinput import split_user_input
56 58
57 59 from IPython.extensions import pickleshare
58 60 from IPython.external.Itpl import ItplNS
@@ -63,8 +65,8 b' from IPython.utils.genutils import *'
63 65 from IPython.utils.strdispatch import StrDispatch
64 66 from IPython.utils.platutils import toggle_set_term_title, set_term_title
65 67
66 from IPython.utils import growl
67 growl.start("IPython")
68 # from IPython.utils import growl
69 # growl.start("IPython")
68 70
69 71 from IPython.utils.traitlets import (
70 72 Int, Float, Str, CBool, CaselessStrEnum, Enum, List, Unicode
@@ -212,7 +214,6 b' class InteractiveShell(Component, Magic):'
212 214 logstart = CBool(False, config_key='LOGSTART')
213 215 logfile = Str('', config_key='LOGFILE')
214 216 logplay = Str('', config_key='LOGPLAY')
215 multi_line_specials = CBool(True, config_key='MULTI_LINE_SPECIALS')
216 217 object_info_string_level = Enum((0,1,2), default_value=0,
217 218 config_keys='OBJECT_INFO_STRING_LEVEL')
218 219 pager = Str('less', config_key='PAGER')
@@ -297,7 +298,7 b' class InteractiveShell(Component, Magic):'
297 298
298 299 self.init_history()
299 300 self.init_encoding()
300 self.init_handlers()
301 self.init_prefilter()
301 302
302 303 Magic.__init__(self, self)
303 304
@@ -1595,7 +1596,7 b' class InteractiveShell(Component, Magic):'
1595 1596
1596 1597 args = arg_s.split(' ',1)
1597 1598 magic_name = args[0]
1598 magic_name = magic_name.lstrip(self.ESC_MAGIC)
1599 magic_name = magic_name.lstrip(prefilter.ESC_MAGIC)
1599 1600
1600 1601 try:
1601 1602 magic_args = args[1]
@@ -1608,7 +1609,6 b' class InteractiveShell(Component, Magic):'
1608 1609 magic_args = self.var_expand(magic_args,1)
1609 1610 with nested(self.builtin_trap, self.display_trap):
1610 1611 return fn(magic_args)
1611 # return result
1612 1612
1613 1613 def define_magic(self, magicname, func):
1614 1614 """Expose own function as magic function for ipython
@@ -1667,58 +1667,6 b' class InteractiveShell(Component, Magic):'
1667 1667 def init_alias(self):
1668 1668 self.alias_manager = AliasManager(self, config=self.config)
1669 1669
1670 def expand_alias(self, line):
1671 """ Expand an alias in the command line
1672
1673 Returns the provided command line, possibly with the first word
1674 (command) translated according to alias expansion rules.
1675
1676 [ipython]|16> _ip.expand_aliases("np myfile.txt")
1677 <16> 'q:/opt/np/notepad++.exe myfile.txt'
1678 """
1679
1680 pre,fn,rest = self.split_user_input(line)
1681 res = pre + self.expand_aliases(fn, rest)
1682 return res
1683
1684 def expand_aliases(self, fn, rest):
1685 """Expand multiple levels of aliases:
1686
1687 if:
1688
1689 alias foo bar /tmp
1690 alias baz foo
1691
1692 then:
1693
1694 baz huhhahhei -> bar /tmp huhhahhei
1695
1696 """
1697 line = fn + " " + rest
1698
1699 done = set()
1700 while 1:
1701 pre,fn,rest = prefilter.splitUserInput(line,
1702 prefilter.shell_line_split)
1703 if fn in self.alias_manager.alias_table:
1704 if fn in done:
1705 warn("Cyclic alias definition, repeated '%s'" % fn)
1706 return ""
1707 done.add(fn)
1708
1709 l2 = self.alias_manager.transform_alias(fn, rest)
1710 if l2 == line:
1711 break
1712 # ls -> ls -F should not recurse forever
1713 if l2.split(None,1)[0] == line.split(None,1)[0]:
1714 line = l2
1715 break
1716 line=l2
1717 else:
1718 break
1719
1720 return line
1721
1722 1670 #-------------------------------------------------------------------------
1723 1671 # Things related to the running of code
1724 1672 #-------------------------------------------------------------------------
@@ -1774,7 +1722,7 b' class InteractiveShell(Component, Magic):'
1774 1722 This emulates Python's -c option."""
1775 1723
1776 1724 #sys.argv = ['-c']
1777 self.push_line(self.prefilter(self.c, False))
1725 self.push_line(self.prefilter_manager.prefilter_lines(self.c, False))
1778 1726 if not self.interactive:
1779 1727 self.ask_exit()
1780 1728
@@ -1807,7 +1755,7 b' class InteractiveShell(Component, Magic):'
1807 1755 """
1808 1756 if line.lstrip() == line:
1809 1757 self.shadowhist.add(line.strip())
1810 lineout = self.prefilter(line,self.more)
1758 lineout = self.prefilter_manager.prefilter_lines(line,self.more)
1811 1759
1812 1760 if line.strip():
1813 1761 if self.more:
@@ -2154,7 +2102,7 b' class InteractiveShell(Component, Magic):'
2154 2102 if line or more:
2155 2103 # push to raw history, so hist line numbers stay in sync
2156 2104 self.input_hist_raw.append("# " + line + "\n")
2157 more = self.push_line(self.prefilter(line,more))
2105 more = self.push_line(self.prefilter_manager.prefilter_lines(line,more))
2158 2106 # IPython's runsource returns None if there was an error
2159 2107 # compiling the code. This allows us to stop processing right
2160 2108 # away, so the user gets the error message at the right place.
@@ -2319,10 +2267,6 b' class InteractiveShell(Component, Magic):'
2319 2267 else:
2320 2268 self.indent_current_nsp = 0
2321 2269
2322 def split_user_input(self, line):
2323 # This is really a hold-over to support ipapi and some extensions
2324 return prefilter.splitUserInput(line)
2325
2326 2270 def resetbuffer(self):
2327 2271 """Reset the input buffer."""
2328 2272 self.buffer[:] = []
@@ -2340,7 +2284,8 b' class InteractiveShell(Component, Magic):'
2340 2284 - continue_prompt(False): whether this line is the first one or a
2341 2285 continuation in a sequence of inputs.
2342 2286 """
2343 growl.notify("raw_input: ", "prompt = %r\ncontinue_prompt = %s" % (prompt, continue_prompt))
2287 # growl.notify("raw_input: ", "prompt = %r\ncontinue_prompt = %s" % (prompt, continue_prompt))
2288
2344 2289 # Code run by the user may have modified the readline completer state.
2345 2290 # We must ensure that our completer is back in place.
2346 2291
@@ -2388,7 +2333,7 b' class InteractiveShell(Component, Magic):'
2388 2333 elif not continue_prompt:
2389 2334 self.input_hist_raw.append('\n')
2390 2335 try:
2391 lineout = self.prefilter(line,continue_prompt)
2336 lineout = self.prefilter_manager.prefilter_lines(line,continue_prompt)
2392 2337 except:
2393 2338 # blanket except, in case a user-defined prefilter crashes, so it
2394 2339 # can't take all of ipython with it.
@@ -2451,293 +2396,8 b' class InteractiveShell(Component, Magic):'
2451 2396 # Things related to the prefilter
2452 2397 #-------------------------------------------------------------------------
2453 2398
2454 def init_handlers(self):
2455 # escapes for automatic behavior on the command line
2456 self.ESC_SHELL = '!'
2457 self.ESC_SH_CAP = '!!'
2458 self.ESC_HELP = '?'
2459 self.ESC_MAGIC = '%'
2460 self.ESC_QUOTE = ','
2461 self.ESC_QUOTE2 = ';'
2462 self.ESC_PAREN = '/'
2463
2464 # And their associated handlers
2465 self.esc_handlers = {self.ESC_PAREN : self.handle_auto,
2466 self.ESC_QUOTE : self.handle_auto,
2467 self.ESC_QUOTE2 : self.handle_auto,
2468 self.ESC_MAGIC : self.handle_magic,
2469 self.ESC_HELP : self.handle_help,
2470 self.ESC_SHELL : self.handle_shell_escape,
2471 self.ESC_SH_CAP : self.handle_shell_escape,
2472 }
2473
2474 def _prefilter(self, line, continue_prompt):
2475 """Calls different preprocessors, depending on the form of line."""
2476
2477 # All handlers *must* return a value, even if it's blank ('').
2478
2479 # Lines are NOT logged here. Handlers should process the line as
2480 # needed, update the cache AND log it (so that the input cache array
2481 # stays synced).
2482
2483 #.....................................................................
2484 # Code begins
2485
2486 #if line.startswith('%crash'): raise RuntimeError,'Crash now!' # dbg
2487
2488 # save the line away in case we crash, so the post-mortem handler can
2489 # record it
2490 growl.notify("_prefilter: ", "line = %s\ncontinue_prompt = %s" % (line, continue_prompt))
2491
2492 self._last_input_line = line
2493
2494 #print '***line: <%s>' % line # dbg
2495
2496 if not line:
2497 # Return immediately on purely empty lines, so that if the user
2498 # previously typed some whitespace that started a continuation
2499 # prompt, he can break out of that loop with just an empty line.
2500 # This is how the default python prompt works.
2501
2502 # Only return if the accumulated input buffer was just whitespace!
2503 if ''.join(self.buffer).isspace():
2504 self.buffer[:] = []
2505 return ''
2506
2507 line_info = prefilter.LineInfo(line, continue_prompt)
2508
2509 # the input history needs to track even empty lines
2510 stripped = line.strip()
2511
2512 if not stripped:
2513 if not continue_prompt:
2514 self.outputcache.prompt_count -= 1
2515 return self.handle_normal(line_info)
2516
2517 # print '***cont',continue_prompt # dbg
2518 # special handlers are only allowed for single line statements
2519 if continue_prompt and not self.multi_line_specials:
2520 return self.handle_normal(line_info)
2521
2522
2523 # See whether any pre-existing handler can take care of it
2524 rewritten = self.hooks.input_prefilter(stripped)
2525 if rewritten != stripped: # ok, some prefilter did something
2526 rewritten = line_info.pre + rewritten # add indentation
2527 return self.handle_normal(prefilter.LineInfo(rewritten,
2528 continue_prompt))
2529
2530 #print 'pre <%s> iFun <%s> rest <%s>' % (pre,iFun,theRest) # dbg
2531
2532 return prefilter.prefilter(line_info, self)
2533
2534
2535 def _prefilter_dumb(self, line, continue_prompt):
2536 """simple prefilter function, for debugging"""
2537 return self.handle_normal(line,continue_prompt)
2538
2539
2540 def multiline_prefilter(self, line, continue_prompt):
2541 """ Run _prefilter for each line of input
2542
2543 Covers cases where there are multiple lines in the user entry,
2544 which is the case when the user goes back to a multiline history
2545 entry and presses enter.
2546
2547 """
2548 growl.notify("multiline_prefilter: ", "%s\n%s" % (line, continue_prompt))
2549 out = []
2550 for l in line.rstrip('\n').split('\n'):
2551 out.append(self._prefilter(l, continue_prompt))
2552 growl.notify("multiline_prefilter return: ", '\n'.join(out))
2553 return '\n'.join(out)
2554
2555 # Set the default prefilter() function (this can be user-overridden)
2556 prefilter = multiline_prefilter
2557
2558 def handle_normal(self, line_info):
2559 """Handle normal input lines. Use as a template for handlers."""
2560
2561 # With autoindent on, we need some way to exit the input loop, and I
2562 # don't want to force the user to have to backspace all the way to
2563 # clear the line. The rule will be in this case, that either two
2564 # lines of pure whitespace in a row, or a line of pure whitespace but
2565 # of a size different to the indent level, will exit the input loop.
2566 line = line_info.line
2567 continue_prompt = line_info.continue_prompt
2568
2569 if (continue_prompt and self.autoindent and line.isspace() and
2570 (0 < abs(len(line) - self.indent_current_nsp) <= 2 or
2571 (self.buffer[-1]).isspace() )):
2572 line = ''
2573
2574 self.log(line,line,continue_prompt)
2575 return line
2576
2577 def handle_alias(self, line_info):
2578 """Handle alias input lines. """
2579 tgt = self.alias_manager.alias_table[line_info.iFun]
2580 if callable(tgt):
2581 if '$' in line_info.line:
2582 call_meth = '(_ip, _ip.var_expand(%s))'
2583 else:
2584 call_meth = '(_ip,%s)'
2585 line_out = ("%s_sh.%s" + call_meth) % (line_info.preWhitespace,
2586 line_info.iFun,
2587 make_quoted_expr(line_info.line))
2588 else:
2589 transformed = self.expand_aliases(line_info.iFun,line_info.theRest)
2590
2591 # pre is needed, because it carries the leading whitespace. Otherwise
2592 # aliases won't work in indented sections.
2593 line_out = '%s_ip.system(%s)' % (line_info.preWhitespace,
2594 make_quoted_expr( transformed ))
2595
2596 self.log(line_info.line,line_out,line_info.continue_prompt)
2597 #print 'line out:',line_out # dbg
2598 return line_out
2599
2600 def handle_shell_escape(self, line_info):
2601 """Execute the line in a shell, empty return value"""
2602 #print 'line in :', `line` # dbg
2603 line = line_info.line
2604 if line.lstrip().startswith('!!'):
2605 # rewrite LineInfo's line, iFun and theRest to properly hold the
2606 # call to %sx and the actual command to be executed, so
2607 # handle_magic can work correctly. Note that this works even if
2608 # the line is indented, so it handles multi_line_specials
2609 # properly.
2610 new_rest = line.lstrip()[2:]
2611 line_info.line = '%ssx %s' % (self.ESC_MAGIC,new_rest)
2612 line_info.iFun = 'sx'
2613 line_info.theRest = new_rest
2614 return self.handle_magic(line_info)
2615 else:
2616 cmd = line.lstrip().lstrip('!')
2617 line_out = '%s_ip.system(%s)' % (line_info.preWhitespace,
2618 make_quoted_expr(cmd))
2619 # update cache/log and return
2620 self.log(line,line_out,line_info.continue_prompt)
2621 return line_out
2622
2623 def handle_magic(self, line_info):
2624 """Execute magic functions."""
2625 iFun = line_info.iFun
2626 theRest = line_info.theRest
2627 cmd = '%s_ip.magic(%s)' % (line_info.preWhitespace,
2628 make_quoted_expr(iFun + " " + theRest))
2629 self.log(line_info.line,cmd,line_info.continue_prompt)
2630 #print 'in handle_magic, cmd=<%s>' % cmd # dbg
2631 return cmd
2632
2633 def handle_auto(self, line_info):
2634 """Hande lines which can be auto-executed, quoting if requested."""
2635
2636 line = line_info.line
2637 iFun = line_info.iFun
2638 theRest = line_info.theRest
2639 pre = line_info.pre
2640 continue_prompt = line_info.continue_prompt
2641 obj = line_info.ofind(self)['obj']
2642
2643 #print 'pre <%s> iFun <%s> rest <%s>' % (pre,iFun,theRest) # dbg
2644
2645 # This should only be active for single-line input!
2646 if continue_prompt:
2647 self.log(line,line,continue_prompt)
2648 return line
2649
2650 force_auto = isinstance(obj, IPyAutocall)
2651 auto_rewrite = True
2652
2653 if pre == self.ESC_QUOTE:
2654 # Auto-quote splitting on whitespace
2655 newcmd = '%s("%s")' % (iFun,'", "'.join(theRest.split()) )
2656 elif pre == self.ESC_QUOTE2:
2657 # Auto-quote whole string
2658 newcmd = '%s("%s")' % (iFun,theRest)
2659 elif pre == self.ESC_PAREN:
2660 newcmd = '%s(%s)' % (iFun,",".join(theRest.split()))
2661 else:
2662 # Auto-paren.
2663 # We only apply it to argument-less calls if the autocall
2664 # parameter is set to 2. We only need to check that autocall is <
2665 # 2, since this function isn't called unless it's at least 1.
2666 if not theRest and (self.autocall < 2) and not force_auto:
2667 newcmd = '%s %s' % (iFun,theRest)
2668 auto_rewrite = False
2669 else:
2670 if not force_auto and theRest.startswith('['):
2671 if hasattr(obj,'__getitem__'):
2672 # Don't autocall in this case: item access for an object
2673 # which is BOTH callable and implements __getitem__.
2674 newcmd = '%s %s' % (iFun,theRest)
2675 auto_rewrite = False
2676 else:
2677 # if the object doesn't support [] access, go ahead and
2678 # autocall
2679 newcmd = '%s(%s)' % (iFun.rstrip(),theRest)
2680 elif theRest.endswith(';'):
2681 newcmd = '%s(%s);' % (iFun.rstrip(),theRest[:-1])
2682 else:
2683 newcmd = '%s(%s)' % (iFun.rstrip(), theRest)
2684
2685 if auto_rewrite:
2686 rw = self.outputcache.prompt1.auto_rewrite() + newcmd
2687
2688 try:
2689 # plain ascii works better w/ pyreadline, on some machines, so
2690 # we use it and only print uncolored rewrite if we have unicode
2691 rw = str(rw)
2692 print >>Term.cout, rw
2693 except UnicodeEncodeError:
2694 print "-------------->" + newcmd
2695
2696 # log what is now valid Python, not the actual user input (without the
2697 # final newline)
2698 self.log(line,newcmd,continue_prompt)
2699 return newcmd
2700
2701 def handle_help(self, line_info):
2702 """Try to get some help for the object.
2703
2704 obj? or ?obj -> basic information.
2705 obj?? or ??obj -> more details.
2706 """
2707
2708 line = line_info.line
2709 # We need to make sure that we don't process lines which would be
2710 # otherwise valid python, such as "x=1 # what?"
2711 try:
2712 codeop.compile_command(line)
2713 except SyntaxError:
2714 # We should only handle as help stuff which is NOT valid syntax
2715 if line[0]==self.ESC_HELP:
2716 line = line[1:]
2717 elif line[-1]==self.ESC_HELP:
2718 line = line[:-1]
2719 self.log(line,'#?'+line,line_info.continue_prompt)
2720 if line:
2721 #print 'line:<%r>' % line # dbg
2722 self.magic_pinfo(line)
2723 else:
2724 page(self.usage,screen_lines=self.usable_screen_length)
2725 return '' # Empty string is needed here!
2726 except:
2727 # Pass any other exceptions through to the normal handler
2728 return self.handle_normal(line_info)
2729 else:
2730 # If the code compiles ok, we should handle it normally
2731 return self.handle_normal(line_info)
2732
2733 def handle_emacs(self, line_info):
2734 """Handle input lines marked by python-mode."""
2735
2736 # Currently, nothing is done. Later more functionality can be added
2737 # here if needed.
2738
2739 # The input cache shouldn't be updated
2740 return line_info.line
2399 def init_prefilter(self):
2400 self.prefilter_manager = PrefilterManager(self, config=self.config)
2741 2401
2742 2402 #-------------------------------------------------------------------------
2743 2403 # Utilities
@@ -2844,6 +2504,3 b' class InteractiveShell(Component, Magic):'
2844 2504 self.restore_sys_module_state()
2845 2505
2846 2506
2847
2848
2849
This diff has been collapsed as it changes many lines, (932 lines changed) Show them Hide them
@@ -1,14 +1,96 b''
1 # -*- coding: utf-8 -*-
1 #!/usr/bin/env python
2 # encoding: utf-8
2 3 """
3 Classes and functions for prefiltering (transforming) a line of user input.
4 This module is responsible, primarily, for breaking the line up into useful
5 pieces and triggering the appropriate handlers in iplib to do the actual
6 transforming work.
4 Prefiltering components.
5
6 Authors:
7
8 * Brian Granger
9 * Fernando Perez
10 * Dan Milstein
7 11 """
8 __docformat__ = "restructuredtext en"
9 12
13 #-----------------------------------------------------------------------------
14 # Copyright (C) 2008-2009 The IPython Development Team
15 #
16 # Distributed under the terms of the BSD License. The full license is in
17 # the file COPYING, distributed as part of this software.
18 #-----------------------------------------------------------------------------
19
20 #-----------------------------------------------------------------------------
21 # Imports
22 #-----------------------------------------------------------------------------
23
24 import __builtin__
25 import codeop
26 import keyword
27 import os
10 28 import re
29 import sys
30
31 from IPython.core.alias import AliasManager
11 32 from IPython.core.autocall import IPyAutocall
33 from IPython.core.component import Component
34 from IPython.core.splitinput import split_user_input
35
36 from IPython.utils.traitlets import List, Int, Any, Str, CBool
37 from IPython.utils.genutils import make_quoted_expr
38 from IPython.utils.autoattr import auto_attr
39
40 #-----------------------------------------------------------------------------
41 # Global utilities, errors and constants
42 #-----------------------------------------------------------------------------
43
44
45 ESC_SHELL = '!'
46 ESC_SH_CAP = '!!'
47 ESC_HELP = '?'
48 ESC_MAGIC = '%'
49 ESC_QUOTE = ','
50 ESC_QUOTE2 = ';'
51 ESC_PAREN = '/'
52
53
54 class PrefilterError(Exception):
55 pass
56
57
58 # RegExp to identify potential function names
59 re_fun_name = re.compile(r'[a-zA-Z_]([a-zA-Z0-9_.]*) *$')
60
61 # RegExp to exclude strings with this start from autocalling. In
62 # particular, all binary operators should be excluded, so that if foo is
63 # callable, foo OP bar doesn't become foo(OP bar), which is invalid. The
64 # characters '!=()' don't need to be checked for, as the checkPythonChars
65 # routine explicitely does so, to catch direct calls and rebindings of
66 # existing names.
67
68 # Warning: the '-' HAS TO BE AT THE END of the first group, otherwise
69 # it affects the rest of the group in square brackets.
70 re_exclude_auto = re.compile(r'^[,&^\|\*/\+-]'
71 r'|^is |^not |^in |^and |^or ')
72
73 # try to catch also methods for stuff in lists/tuples/dicts: off
74 # (experimental). For this to work, the line_split regexp would need
75 # to be modified so it wouldn't break things at '['. That line is
76 # nasty enough that I shouldn't change it until I can test it _well_.
77 #self.re_fun_name = re.compile (r'[a-zA-Z_]([a-zA-Z0-9_.\[\]]*) ?$')
78
79
80 # Handler Check Utilities
81 def is_shadowed(identifier, ip):
82 """Is the given identifier defined in one of the namespaces which shadow
83 the alias and magic namespaces? Note that an identifier is different
84 than ifun, because it can not contain a '.' character."""
85 # This is much safer than calling ofind, which can change state
86 return (identifier in ip.user_ns \
87 or identifier in ip.internal_ns \
88 or identifier in ip.ns_table['builtin'])
89
90
91 #-----------------------------------------------------------------------------
92 # The LineInfo class used throughout
93 #-----------------------------------------------------------------------------
12 94
13 95
14 96 class LineInfo(object):
@@ -25,39 +107,39 b' class LineInfo(object):'
25 107 pre
26 108 The initial esc character or whitespace.
27 109
28 preChar
110 pre_char
29 111 The escape character(s) in pre or the empty string if there isn't one.
30 Note that '!!' is a possible value for preChar. Otherwise it will
112 Note that '!!' is a possible value for pre_char. Otherwise it will
31 113 always be a single character.
32 114
33 preWhitespace
34 The leading whitespace from pre if it exists. If there is a preChar,
115 pre_whitespace
116 The leading whitespace from pre if it exists. If there is a pre_char,
35 117 this is just ''.
36 118
37 iFun
119 ifun
38 120 The 'function part', which is basically the maximal initial sequence
39 121 of valid python identifiers and the '.' character. This is what is
40 122 checked for alias and magic transformations, used for auto-calling,
41 123 etc.
42 124
43 theRest
125 the_rest
44 126 Everything else on the line.
45 127 """
46 128 def __init__(self, line, continue_prompt):
47 129 self.line = line
48 130 self.continue_prompt = continue_prompt
49 self.pre, self.iFun, self.theRest = splitUserInput(line)
131 self.pre, self.ifun, self.the_rest = split_user_input(line)
50 132
51 self.preChar = self.pre.strip()
52 if self.preChar:
53 self.preWhitespace = '' # No whitespace allowd before esc chars
133 self.pre_char = self.pre.strip()
134 if self.pre_char:
135 self.pre_whitespace = '' # No whitespace allowd before esc chars
54 136 else:
55 self.preWhitespace = self.pre
137 self.pre_whitespace = self.pre
56 138
57 139 self._oinfo = None
58 140
59 141 def ofind(self, ip):
60 """Do a full, attribute-walking lookup of the iFun in the various
142 """Do a full, attribute-walking lookup of the ifun in the various
61 143 namespaces for the given IPython InteractiveShell instance.
62 144
63 145 Return a dict with keys: found,obj,ospace,ismagic
@@ -70,252 +152,626 b' class LineInfo(object):'
70 152 without worrying about *further* damaging state.
71 153 """
72 154 if not self._oinfo:
73 self._oinfo = ip._ofind(self.iFun)
155 self._oinfo = ip._ofind(self.ifun)
74 156 return self._oinfo
157
75 158 def __str__(self):
76 return "Lineinfo [%s|%s|%s]" %(self.pre,self.iFun,self.theRest)
159 return "Lineinfo [%s|%s|%s]" %(self.pre,self.ifun,self.the_rest)
160
77 161
78 def splitUserInput(line, pattern=None):
79 """Split user input into pre-char/whitespace, function part and rest.
162 #-----------------------------------------------------------------------------
163 # Main Prefilter manager
164 #-----------------------------------------------------------------------------
80 165
81 Mostly internal to this module, but also used by iplib.expand_aliases,
82 which passes in a shell pattern.
166
167 class PrefilterManager(Component):
168 """Main prefilter component.
169
170 The IPython prefilter is run on all user input before it is run. The
171 prefilter consumes lines of input and produces transformed lines of
172 input. The implementation consists of checkers and handlers. The
173 checkers inspect the input line and select which handler will be used
174 to transform the input line.
83 175 """
84 # It seems to me that the shell splitting should be a separate method.
85
86 if not pattern:
87 pattern = line_split
88 match = pattern.match(line)
89 if not match:
90 #print "match failed for line '%s'" % line
176
177 multi_line_specials = CBool(True, config_key='MULTI_LINE_SPECIALS')
178
179 def __init__(self, parent, config=None):
180 super(PrefilterManager, self).__init__(parent, config=config)
181 self.init_handlers()
182 self.init_checkers()
183
184 @auto_attr
185 def shell(self):
186 shell = Component.get_instances(
187 root=self.root,
188 klass='IPython.core.iplib.InteractiveShell'
189 )[0]
190 return shell
191
192 def init_checkers(self):
193 self._checkers = []
194 for checker in _default_checkers:
195 self._checkers.append(checker(self, config=self.config))
196
197 def init_handlers(self):
198 self._handlers = {}
199 self._esc_handlers = {}
200 for handler in _default_handlers:
201 handler(self, config=self.config)
202
203 @property
204 def sorted_checkers(self):
205 """Return a list of checkers, sorted by priority."""
206 return sorted(self._checkers, cmp=lambda x,y: x.priority-y.priority)
207
208 def register_handler(self, name, handler, esc_strings):
209 """Register a handler instance by name with esc_strings."""
210 self._handlers[name] = handler
211 for esc_str in esc_strings:
212 self._esc_handlers[esc_str] = handler
213
214 def unregister_handler(self, name, handler, esc_strings):
215 """Unregister a handler instance by name with esc_strings."""
91 216 try:
92 iFun,theRest = line.split(None,1)
93 except ValueError:
94 #print "split failed for line '%s'" % line
95 iFun,theRest = line,''
96 pre = re.match('^(\s*)(.*)',line).groups()[0]
97 else:
98 pre,iFun,theRest = match.groups()
99
100 # iFun has to be a valid python identifier, so it better be only pure
101 # ascii, no unicode:
102 try:
103 iFun = iFun.encode('ascii')
104 except UnicodeEncodeError:
105 theRest = iFun + u' ' + theRest
106 iFun = u''
107
108 #print 'line:<%s>' % line # dbg
109 #print 'pre <%s> iFun <%s> rest <%s>' % (pre,iFun.strip(),theRest) # dbg
110 return pre,iFun.strip(),theRest.lstrip()
111
112
113 # RegExp for splitting line contents into pre-char//first word-method//rest.
114 # For clarity, each group in on one line.
115
116 # WARNING: update the regexp if the escapes in iplib are changed, as they
117 # are hardwired in.
118
119 # Although it's not solely driven by the regex, note that:
120 # ,;/% only trigger if they are the first character on the line
121 # ! and !! trigger if they are first char(s) *or* follow an indent
122 # ? triggers as first or last char.
123
124 # The three parts of the regex are:
125 # 1) pre: pre_char *or* initial whitespace
126 # 2) iFun: first word/method (mix of \w and '.')
127 # 3) theRest: rest of line (separated from iFun by space if non-empty)
128 line_split = re.compile(r'^([,;/%?]|!!?|\s*)'
129 r'\s*([\w\.]+)'
130 r'(\s+.*$|$)')
131
132 shell_line_split = re.compile(r'^(\s*)(\S*\s*)(.*$)')
133
134 def prefilter(line_info, ip):
135 """Call one of the passed-in InteractiveShell's handler preprocessors,
136 depending on the form of the line. Return the results, which must be a
137 value, even if it's a blank ('')."""
138 # Note: the order of these checks does matter.
139 for check in [ checkEmacs,
140 checkShellEscape,
141 checkIPyAutocall,
142 checkMultiLineMagic,
143 checkEscChars,
144 checkAssignment,
145 checkAutomagic,
146 checkAlias,
147 checkPythonOps,
148 checkAutocall,
149 ]:
150 handler = check(line_info, ip)
151 if handler:
152 return handler(line_info)
153
154 return ip.handle_normal(line_info)
155
156 # Handler checks
157 #
158 # All have the same interface: they take a LineInfo object and a ref to the
159 # iplib.InteractiveShell object. They check the line to see if a particular
160 # handler should be called, and return either a handler or None. The
161 # handlers which they return are *bound* methods of the InteractiveShell
162 # object.
163 #
164 # In general, these checks should only take responsibility for their 'own'
165 # handler. If it doesn't get triggered, they should just return None and
166 # let the rest of the check sequence run.
167
168 def checkShellEscape(l_info,ip):
169 if l_info.line.lstrip().startswith(ip.ESC_SHELL):
170 return ip.handle_shell_escape
171
172 def checkEmacs(l_info,ip):
173 "Emacs ipython-mode tags certain input lines."
174 if l_info.line.endswith('# PYTHON-MODE'):
175 return ip.handle_emacs
176 else:
177 return None
217 del self._handlers[name]
218 except KeyError:
219 pass
220 for esc_str in esc_strings:
221 h = self._esc_handlers.get(esc_str)
222 if h is handler:
223 del self._esc_handlers[esc_str]
224
225 def get_handler_by_name(self, name):
226 """Get a handler by its name."""
227 return self._handlers.get(name)
228
229 def get_handler_by_esc(self, esc_str):
230 """Get a handler by its escape string."""
231 return self._esc_handlers.get(esc_str)
232
233 def prefilter_line_info(self, line_info):
234 """Prefilter a line that has been converted to a LineInfo object."""
235 handler = self.find_handler(line_info)
236 return handler.handle(line_info)
237
238 def find_handler(self, line_info):
239 """Find a handler for the line_info by trying checkers."""
240 for checker in self.sorted_checkers:
241 handler = checker.check(line_info)
242 if handler:
243 return handler
244 return self.get_handler_by_name('normal')
245
246 def prefilter_line(self, line, continue_prompt):
247 """Prefilter a single input line as text."""
248
249 # All handlers *must* return a value, even if it's blank ('').
250
251 # Lines are NOT logged here. Handlers should process the line as
252 # needed, update the cache AND log it (so that the input cache array
253 # stays synced).
254
255 # growl.notify("_prefilter: ", "line = %s\ncontinue_prompt = %s" % (line, continue_prompt))
256
257 # save the line away in case we crash, so the post-mortem handler can
258 # record it
259 self.shell._last_input_line = line
260
261 if not line:
262 # Return immediately on purely empty lines, so that if the user
263 # previously typed some whitespace that started a continuation
264 # prompt, he can break out of that loop with just an empty line.
265 # This is how the default python prompt works.
266
267 # Only return if the accumulated input buffer was just whitespace!
268 if ''.join(self.shell.buffer).isspace():
269 self.shell.buffer[:] = []
270 return ''
271
272 line_info = LineInfo(line, continue_prompt)
273
274 # the input history needs to track even empty lines
275 stripped = line.strip()
178 276
179 def checkIPyAutocall(l_info,ip):
180 "Instances of IPyAutocall in user_ns get autocalled immediately"
181 obj = ip.user_ns.get(l_info.iFun, None)
182 if isinstance(obj, IPyAutocall):
183 obj.set_ip(ip)
184 return ip.handle_auto
185 else:
186 return None
187
188
189 def checkMultiLineMagic(l_info,ip):
190 "Allow ! and !! in multi-line statements if multi_line_specials is on"
191 # Note that this one of the only places we check the first character of
192 # iFun and *not* the preChar. Also note that the below test matches
193 # both ! and !!.
194 if l_info.continue_prompt \
195 and ip.multi_line_specials:
196 if l_info.iFun.startswith(ip.ESC_MAGIC):
197 return ip.handle_magic
198 else:
199 return None
277 handle_normal = self.get_handler_by_name('normal')
278 if not stripped:
279 if not continue_prompt:
280 self.shell.outputcache.prompt_count -= 1
200 281
201 def checkEscChars(l_info,ip):
202 """Check for escape character and return either a handler to handle it,
203 or None if there is no escape char."""
204 if l_info.line[-1] == ip.ESC_HELP \
205 and l_info.preChar != ip.ESC_SHELL \
206 and l_info.preChar != ip.ESC_SH_CAP:
207 # the ? can be at the end, but *not* for either kind of shell escape,
208 # because a ? can be a vaild final char in a shell cmd
209 return ip.handle_help
210 elif l_info.preChar in ip.esc_handlers:
211 return ip.esc_handlers[l_info.preChar]
212 else:
213 return None
282 return handle_normal(line_info)
214 283
284 # special handlers are only allowed for single line statements
285 if continue_prompt and not self.multi_line_specials:
286 return handle_normal(line_info)
215 287
216 def checkAssignment(l_info,ip):
217 """Check to see if user is assigning to a var for the first time, in
218 which case we want to avoid any sort of automagic / autocall games.
219
220 This allows users to assign to either alias or magic names true python
221 variables (the magic/alias systems always take second seat to true
222 python code). E.g. ls='hi', or ls,that=1,2"""
223 if l_info.theRest and l_info.theRest[0] in '=,':
224 return ip.handle_normal
225 else:
226 return None
288 return self.prefilter_line_info(line_info)
227 289
290 def prefilter_lines(self, lines, continue_prompt):
291 """Prefilter multiple input lines of text.
228 292
229 def checkAutomagic(l_info,ip):
230 """If the iFun is magic, and automagic is on, run it. Note: normal,
231 non-auto magic would already have been triggered via '%' in
232 check_esc_chars. This just checks for automagic. Also, before
233 triggering the magic handler, make sure that there is nothing in the
234 user namespace which could shadow it."""
235 if not ip.automagic or not hasattr(ip,'magic_'+l_info.iFun):
236 return None
293 Covers cases where there are multiple lines in the user entry,
294 which is the case when the user goes back to a multiline history
295 entry and presses enter.
296 """
297 # growl.notify("multiline_prefilter: ", "%s\n%s" % (line, continue_prompt))
298 out = []
299 for line in lines.rstrip('\n').split('\n'):
300 out.append(self.prefilter_line(line, continue_prompt))
301 # growl.notify("multiline_prefilter return: ", '\n'.join(out))
302 return '\n'.join(out)
237 303
238 # We have a likely magic method. Make sure we should actually call it.
239 if l_info.continue_prompt and not ip.multi_line_specials:
240 return None
241 304
242 head = l_info.iFun.split('.',1)[0]
243 if isShadowed(head,ip):
244 return None
305 #-----------------------------------------------------------------------------
306 # Prefilter checkers
307 #-----------------------------------------------------------------------------
245 308
246 return ip.handle_magic
247 309
248
249 def checkAlias(l_info,ip):
250 "Check if the initital identifier on the line is an alias."
251 # Note: aliases can not contain '.'
252 head = l_info.iFun.split('.',1)[0]
253
254 if l_info.iFun not in ip.alias_manager \
255 or head not in ip.alias_manager \
256 or isShadowed(head,ip):
257 return None
310 class PrefilterChecker(Component):
311 """Inspect an input line and return a handler for that line."""
258 312
259 return ip.handle_alias
313 priority = Int(100)
314 shell = Any
315 prefilter_manager = Any
260 316
317 def __init__(self, parent, config=None):
318 super(PrefilterChecker, self).__init__(parent, config=config)
261 319
262 def checkPythonOps(l_info,ip):
263 """If the 'rest' of the line begins with a function call or pretty much
264 any python operator, we should simply execute the line (regardless of
265 whether or not there's a possible autocall expansion). This avoids
266 spurious (and very confusing) geattr() accesses."""
267 if l_info.theRest and l_info.theRest[0] in '!=()<>,+*/%^&|':
268 return ip.handle_normal
269 else:
270 return None
320 @auto_attr
321 def shell(self):
322 shell = Component.get_instances(
323 root=self.root,
324 klass='IPython.core.iplib.InteractiveShell'
325 )[0]
326 return shell
271 327
328 @auto_attr
329 def prefilter_manager(self):
330 return PrefilterManager.get_instances(root=self.root)[0]
272 331
273 def checkAutocall(l_info,ip):
274 "Check if the initial word/function is callable and autocall is on."
275 if not ip.autocall:
332 def check(self, line_info):
333 """Inspect line_info and return a handler or None."""
276 334 return None
277 335
278 oinfo = l_info.ofind(ip) # This can mutate state via getattr
279 if not oinfo['found']:
280 return None
281
282 if callable(oinfo['obj']) \
283 and (not re_exclude_auto.match(l_info.theRest)) \
284 and re_fun_name.match(l_info.iFun):
285 #print 'going auto' # dbg
286 return ip.handle_auto
287 else:
288 #print 'was callable?', callable(l_info.oinfo['obj']) # dbg
289 return None
336
337 class EmacsChecker(PrefilterChecker):
338
339 priority = Int(100)
340
341 def check(self, line_info):
342 "Emacs ipython-mode tags certain input lines."
343 if line_info.line.endswith('# PYTHON-MODE'):
344 return self.prefilter_manager.get_handler_by_name('emacs')
345 else:
346 return None
347
348
349 class ShellEscapeChecker(PrefilterChecker):
350
351 priority = Int(200)
352
353 def check(self, line_info):
354 if line_info.line.lstrip().startswith(ESC_SHELL):
355 return self.prefilter_manager.get_handler_by_name('shell')
356
357
358 class IPyAutocallChecker(PrefilterChecker):
359
360 priority = Int(300)
361
362 def check(self, line_info):
363 "Instances of IPyAutocall in user_ns get autocalled immediately"
364 obj = self.shell.user_ns.get(line_info.ifun, None)
365 if isinstance(obj, IPyAutocall):
366 obj.set_ip(self.shell)
367 return self.prefilter_manager.get_handler_by_name('auto')
368 else:
369 return None
370
371
372 class MultiLineMagicChecker(PrefilterChecker):
373
374 priority = Int(400)
375
376 def check(self, line_info):
377 "Allow ! and !! in multi-line statements if multi_line_specials is on"
378 # Note that this one of the only places we check the first character of
379 # ifun and *not* the pre_char. Also note that the below test matches
380 # both ! and !!.
381 if line_info.continue_prompt \
382 and self.prefilter_manager.multi_line_specials:
383 if line_info.ifun.startswith(ESC_MAGIC):
384 return self.prefilter_manager.get_handler_by_name('magic')
385 else:
386 return None
387
388
389 class EscCharsChecker(PrefilterChecker):
390
391 priority = Int(500)
392
393 def check(self, line_info):
394 """Check for escape character and return either a handler to handle it,
395 or None if there is no escape char."""
396 if line_info.line[-1] == ESC_HELP \
397 and line_info.pre_char != ESC_SHELL \
398 and line_info.pre_char != ESC_SH_CAP:
399 # the ? can be at the end, but *not* for either kind of shell escape,
400 # because a ? can be a vaild final char in a shell cmd
401 return self.prefilter_manager.get_handler_by_name('help')
402 else:
403 # This returns None like it should if no handler exists
404 return self.prefilter_manager.get_handler_by_esc(line_info.pre_char)
405
406
407 class AssignmentChecker(PrefilterChecker):
408
409 priority = Int(600)
410
411 def check(self, line_info):
412 """Check to see if user is assigning to a var for the first time, in
413 which case we want to avoid any sort of automagic / autocall games.
290 414
291 # RegExp to identify potential function names
292 re_fun_name = re.compile(r'[a-zA-Z_]([a-zA-Z0-9_.]*) *$')
415 This allows users to assign to either alias or magic names true python
416 variables (the magic/alias systems always take second seat to true
417 python code). E.g. ls='hi', or ls,that=1,2"""
418 if line_info.the_rest and line_info.the_rest[0] in '=,':
419 return self.prefilter_manager.get_handler_by_name('normal')
420 else:
421 return None
293 422
294 # RegExp to exclude strings with this start from autocalling. In
295 # particular, all binary operators should be excluded, so that if foo is
296 # callable, foo OP bar doesn't become foo(OP bar), which is invalid. The
297 # characters '!=()' don't need to be checked for, as the checkPythonChars
298 # routine explicitely does so, to catch direct calls and rebindings of
299 # existing names.
300 423
301 # Warning: the '-' HAS TO BE AT THE END of the first group, otherwise
302 # it affects the rest of the group in square brackets.
303 re_exclude_auto = re.compile(r'^[,&^\|\*/\+-]'
304 r'|^is |^not |^in |^and |^or ')
424 class AutoMagicChecker(PrefilterChecker):
305 425
306 # try to catch also methods for stuff in lists/tuples/dicts: off
307 # (experimental). For this to work, the line_split regexp would need
308 # to be modified so it wouldn't break things at '['. That line is
309 # nasty enough that I shouldn't change it until I can test it _well_.
310 #self.re_fun_name = re.compile (r'[a-zA-Z_]([a-zA-Z0-9_.\[\]]*) ?$')
426 priority = Int(700)
311 427
312 # Handler Check Utilities
313 def isShadowed(identifier,ip):
314 """Is the given identifier defined in one of the namespaces which shadow
315 the alias and magic namespaces? Note that an identifier is different
316 than iFun, because it can not contain a '.' character."""
317 # This is much safer than calling ofind, which can change state
318 return (identifier in ip.user_ns \
319 or identifier in ip.internal_ns \
320 or identifier in ip.ns_table['builtin'])
428 def check(self, line_info):
429 """If the ifun is magic, and automagic is on, run it. Note: normal,
430 non-auto magic would already have been triggered via '%' in
431 check_esc_chars. This just checks for automagic. Also, before
432 triggering the magic handler, make sure that there is nothing in the
433 user namespace which could shadow it."""
434 if not self.shell.automagic or not hasattr(self.shell,'magic_'+line_info.ifun):
435 return None
436
437 # We have a likely magic method. Make sure we should actually call it.
438 if line_info.continue_prompt and not self.shell.multi_line_specials:
439 return None
440
441 head = line_info.ifun.split('.',1)[0]
442 if is_shadowed(head, self.shell):
443 return None
444
445 return self.prefilter_manager.get_handler_by_name('magic')
446
447
448 class AliasChecker(PrefilterChecker):
449
450 priority = Int(800)
451
452 @auto_attr
453 def alias_manager(self):
454 return AliasManager.get_instances(root=self.root)[0]
455
456 def check(self, line_info):
457 "Check if the initital identifier on the line is an alias."
458 # Note: aliases can not contain '.'
459 head = line_info.ifun.split('.',1)[0]
460 if line_info.ifun not in self.alias_manager \
461 or head not in self.alias_manager \
462 or is_shadowed(head, self.shell):
463 return None
464
465 return self.prefilter_manager.get_handler_by_name('alias')
466
467
468 class PythonOpsChecker(PrefilterChecker):
469
470 priority = Int(900)
471
472 def check(self, line_info):
473 """If the 'rest' of the line begins with a function call or pretty much
474 any python operator, we should simply execute the line (regardless of
475 whether or not there's a possible autocall expansion). This avoids
476 spurious (and very confusing) geattr() accesses."""
477 if line_info.the_rest and line_info.the_rest[0] in '!=()<>,+*/%^&|':
478 return self.prefilter_manager.get_handler_by_name('normal')
479 else:
480 return None
481
482
483 class AutocallChecker(PrefilterChecker):
484
485 priority = Int(1000)
486
487 def check(self, line_info):
488 "Check if the initial word/function is callable and autocall is on."
489 if not self.shell.autocall:
490 return None
491
492 oinfo = line_info.ofind(self.shell) # This can mutate state via getattr
493 if not oinfo['found']:
494 return None
495
496 if callable(oinfo['obj']) \
497 and (not re_exclude_auto.match(line_info.the_rest)) \
498 and re_fun_name.match(line_info.ifun):
499 return self.prefilter_manager.get_handler_by_name('auto')
500 else:
501 return None
502
503
504 #-----------------------------------------------------------------------------
505 # Prefilter handlers
506 #-----------------------------------------------------------------------------
507
508
509 class PrefilterHandler(Component):
510
511 handler_name = Str('normal')
512 esc_strings = List([])
513 shell = Any
514 prefilter_manager = Any
515
516 def __init__(self, parent, config=None):
517 super(PrefilterHandler, self).__init__(parent, config=config)
518 self.prefilter_manager.register_handler(
519 self.handler_name,
520 self,
521 self.esc_strings
522 )
523
524 @auto_attr
525 def shell(self):
526 shell = Component.get_instances(
527 root=self.root,
528 klass='IPython.core.iplib.InteractiveShell'
529 )[0]
530 return shell
531
532 @auto_attr
533 def prefilter_manager(self):
534 return PrefilterManager.get_instances(root=self.root)[0]
535
536 def handle(self, line_info):
537 """Handle normal input lines. Use as a template for handlers."""
538
539 # With autoindent on, we need some way to exit the input loop, and I
540 # don't want to force the user to have to backspace all the way to
541 # clear the line. The rule will be in this case, that either two
542 # lines of pure whitespace in a row, or a line of pure whitespace but
543 # of a size different to the indent level, will exit the input loop.
544 line = line_info.line
545 continue_prompt = line_info.continue_prompt
546
547 if (continue_prompt and self.shell.autoindent and line.isspace() and
548 (0 < abs(len(line) - self.shell.indent_current_nsp) <= 2 or
549 (self.shell.buffer[-1]).isspace() )):
550 line = ''
551
552 self.shell.log(line, line, continue_prompt)
553 return line
554
555
556 class AliasHandler(PrefilterHandler):
557
558 handler_name = Str('alias')
559 esc_strings = List([])
560
561 @auto_attr
562 def alias_manager(self):
563 return AliasManager.get_instances(root=self.root)[0]
564
565 def handle(self, line_info):
566 """Handle alias input lines. """
567 transformed = self.alias_manager.expand_aliases(line_info.ifun,line_info.the_rest)
568 # pre is needed, because it carries the leading whitespace. Otherwise
569 # aliases won't work in indented sections.
570 line_out = '%s_ip.system(%s)' % (line_info.pre_whitespace,
571 make_quoted_expr(transformed))
572
573 self.shell.log(line_info.line, line_out, line_info.continue_prompt)
574 return line_out
575
576
577 class ShellEscapeHandler(PrefilterHandler):
578
579 handler_name = Str('shell')
580 esc_strings = List([ESC_SHELL, ESC_SH_CAP])
581
582 def handle(self, line_info):
583 """Execute the line in a shell, empty return value"""
584 magic_handler = self.prefilter_manager.get_handler_by_name('magic')
585
586 line = line_info.line
587 if line.lstrip().startswith(ESC_SH_CAP):
588 # rewrite LineInfo's line, ifun and the_rest to properly hold the
589 # call to %sx and the actual command to be executed, so
590 # handle_magic can work correctly. Note that this works even if
591 # the line is indented, so it handles multi_line_specials
592 # properly.
593 new_rest = line.lstrip()[2:]
594 line_info.line = '%ssx %s' % (ESC_MAGIC, new_rest)
595 line_info.ifun = 'sx'
596 line_info.the_rest = new_rest
597 return magic_handler.handle(line_info)
598 else:
599 cmd = line.lstrip().lstrip(ESC_SHELL)
600 line_out = '%s_ip.system(%s)' % (line_info.pre_whitespace,
601 make_quoted_expr(cmd))
602 # update cache/log and return
603 self.shell.log(line, line_out, line_info.continue_prompt)
604 return line_out
605
606
607 class MagicHandler(PrefilterHandler):
608
609 handler_name = Str('magic')
610 esc_strings = List(['%'])
611
612 def handle(self, line_info):
613 """Execute magic functions."""
614 ifun = line_info.ifun
615 the_rest = line_info.the_rest
616 cmd = '%s_ip.magic(%s)' % (line_info.pre_whitespace,
617 make_quoted_expr(ifun + " " + the_rest))
618 self.shell.log(line_info.line, cmd, line_info.continue_prompt)
619 return cmd
620
621
622 class AutoHandler(PrefilterHandler):
623
624 handler_name = Str('auto')
625 esc_strings = List([ESC_PAREN, ESC_QUOTE, ESC_QUOTE2])
626
627 def handle(self, line_info):
628 """Hande lines which can be auto-executed, quoting if requested."""
629 line = line_info.line
630 ifun = line_info.ifun
631 the_rest = line_info.the_rest
632 pre = line_info.pre
633 continue_prompt = line_info.continue_prompt
634 obj = line_info.ofind(self)['obj']
635
636 #print 'pre <%s> ifun <%s> rest <%s>' % (pre,ifun,the_rest) # dbg
637
638 # This should only be active for single-line input!
639 if continue_prompt:
640 self.log(line,line,continue_prompt)
641 return line
642
643 force_auto = isinstance(obj, IPyAutocall)
644 auto_rewrite = True
645
646 if pre == ESC_QUOTE:
647 # Auto-quote splitting on whitespace
648 newcmd = '%s("%s")' % (ifun,'", "'.join(the_rest.split()) )
649 elif pre == ESC_QUOTE2:
650 # Auto-quote whole string
651 newcmd = '%s("%s")' % (ifun,the_rest)
652 elif pre == ESC_PAREN:
653 newcmd = '%s(%s)' % (ifun,",".join(the_rest.split()))
654 else:
655 # Auto-paren.
656 # We only apply it to argument-less calls if the autocall
657 # parameter is set to 2. We only need to check that autocall is <
658 # 2, since this function isn't called unless it's at least 1.
659 if not the_rest and (self.autocall < 2) and not force_auto:
660 newcmd = '%s %s' % (ifun,the_rest)
661 auto_rewrite = False
662 else:
663 if not force_auto and the_rest.startswith('['):
664 if hasattr(obj,'__getitem__'):
665 # Don't autocall in this case: item access for an object
666 # which is BOTH callable and implements __getitem__.
667 newcmd = '%s %s' % (ifun,the_rest)
668 auto_rewrite = False
669 else:
670 # if the object doesn't support [] access, go ahead and
671 # autocall
672 newcmd = '%s(%s)' % (ifun.rstrip(),the_rest)
673 elif the_rest.endswith(';'):
674 newcmd = '%s(%s);' % (ifun.rstrip(),the_rest[:-1])
675 else:
676 newcmd = '%s(%s)' % (ifun.rstrip(), the_rest)
677
678 if auto_rewrite:
679 rw = self.shell.outputcache.prompt1.auto_rewrite() + newcmd
680
681 try:
682 # plain ascii works better w/ pyreadline, on some machines, so
683 # we use it and only print uncolored rewrite if we have unicode
684 rw = str(rw)
685 print >>Term.cout, rw
686 except UnicodeEncodeError:
687 print "-------------->" + newcmd
688
689 # log what is now valid Python, not the actual user input (without the
690 # final newline)
691 self.shell.log(line,newcmd,continue_prompt)
692 return newcmd
693
694
695 class HelpHandler(PrefilterHandler):
696
697 handler_name = Str('help')
698 esc_strings = List([ESC_HELP])
699
700 def handle(self, line_info):
701 """Try to get some help for the object.
702
703 obj? or ?obj -> basic information.
704 obj?? or ??obj -> more details.
705 """
706 normal_handler = self.prefilter_manager.get_handler_by_name('normal')
707 line = line_info.line
708 # We need to make sure that we don't process lines which would be
709 # otherwise valid python, such as "x=1 # what?"
710 try:
711 codeop.compile_command(line)
712 except SyntaxError:
713 # We should only handle as help stuff which is NOT valid syntax
714 if line[0]==ESC_HELP:
715 line = line[1:]
716 elif line[-1]==ESC_HELP:
717 line = line[:-1]
718 self.shell.log(line, '#?'+line, line_info.continue_prompt)
719 if line:
720 #print 'line:<%r>' % line # dbg
721 self.shell.magic_pinfo(line)
722 else:
723 page(self.shell.usage, screen_lines=self.shell.usable_screen_length)
724 return '' # Empty string is needed here!
725 except:
726 raise
727 # Pass any other exceptions through to the normal handler
728 return normal_handler.handle(line_info)
729 else:
730 raise
731 # If the code compiles ok, we should handle it normally
732 return normal_handler.handle(line_info)
733
734
735 class EmacsHandler(PrefilterHandler):
736
737 handler_name = Str('emacs')
738 esc_strings = List([])
739
740 def handle(self, line_info):
741 """Handle input lines marked by python-mode."""
742
743 # Currently, nothing is done. Later more functionality can be added
744 # here if needed.
745
746 # The input cache shouldn't be updated
747 return line_info.line
748
749
750 #-----------------------------------------------------------------------------
751 # Defaults
752 #-----------------------------------------------------------------------------
753
754
755 _default_checkers = [
756 EmacsChecker,
757 ShellEscapeChecker,
758 IPyAutocallChecker,
759 MultiLineMagicChecker,
760 EscCharsChecker,
761 AssignmentChecker,
762 AutoMagicChecker,
763 AliasChecker,
764 PythonOpsChecker,
765 AutocallChecker
766 ]
767
768 _default_handlers = [
769 PrefilterHandler,
770 AliasHandler,
771 ShellEscapeHandler,
772 MagicHandler,
773 AutoHandler,
774 HelpHandler,
775 EmacsHandler
776 ]
321 777
General Comments 0
You need to be logged in to leave comments. Login now