##// 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 import __builtin__
22 import __builtin__
23 import keyword
23 import keyword
24 import os
24 import os
25 import re
25 import sys
26 import sys
26
27
27 from IPython.core.component import Component
28 from IPython.core.component import Component
29 from IPython.core.splitinput import split_user_input
28
30
29 from IPython.utils.traitlets import CBool, List, Instance
31 from IPython.utils.traitlets import CBool, List, Instance
30 from IPython.utils.genutils import error
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 def default_aliases():
42 def default_aliases():
37 # Make some aliases automatically
43 # Make some aliases automatically
38 # Prepare list of shell aliases to auto-define
44 # Prepare list of shell aliases to auto-define
@@ -88,6 +94,11 b' class InvalidAliasError(AliasError):'
88 pass
94 pass
89
95
90
96
97 #-----------------------------------------------------------------------------
98 # Main AliasManager class
99 #-----------------------------------------------------------------------------
100
101
91 class AliasManager(Component):
102 class AliasManager(Component):
92
103
93 auto_alias = List(default_aliases())
104 auto_alias = List(default_aliases())
@@ -95,14 +106,18 b' class AliasManager(Component):'
95
106
96 def __init__(self, parent, config=None):
107 def __init__(self, parent, config=None):
97 super(AliasManager, self).__init__(parent, config=config)
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 self.alias_table = {}
109 self.alias_table = {}
103 self.exclude_aliases()
110 self.exclude_aliases()
104 self.init_aliases()
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 def __contains__(self, name):
121 def __contains__(self, name):
107 if name in self.alias_table:
122 if name in self.alias_table:
108 return True
123 return True
@@ -189,3 +204,54 b' class AliasManager(Component):'
189 (alias, nargs, len(args)))
204 (alias, nargs, len(args)))
190 cmd = '%s %s' % (cmd % tuple(args[:nargs]),' '.join(args[nargs:]))
205 cmd = '%s %s' % (cmd % tuple(args[:nargs]),' '.join(args[nargs:]))
191 return cmd
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 from IPython.core.component import Component
24 from IPython.core.component import Component
25 from IPython.core.quitter import Quitter
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 # Classes and functions
30 # Classes and functions
@@ -39,12 +39,15 b' class BuiltinTrap(Component):'
39
39
40 def __init__(self, parent):
40 def __init__(self, parent):
41 super(BuiltinTrap, self).__init__(parent, None, None)
41 super(BuiltinTrap, self).__init__(parent, None, None)
42 # Don't just grab parent!!!
42 self._orig_builtins = {}
43 self.shell = Component.get_instances(
43
44 @auto_attr
45 def shell(self):
46 shell = Component.get_instances(
44 root=self.root,
47 root=self.root,
45 klass='IPython.core.iplib.InteractiveShell'
48 klass='IPython.core.iplib.InteractiveShell'
46 )[0]
49 )[0]
47 self._orig_builtins = {}
50 return shell
48
51
49 def __enter__(self):
52 def __enter__(self):
50 self.set()
53 self.set()
@@ -74,7 +74,9 b' import itertools'
74 import types
74 import types
75
75
76 from IPython.core.error import TryNext
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 from IPython.utils.ipstruct import Struct
80 from IPython.utils.ipstruct import Struct
79 from IPython.utils import generics
81 from IPython.utils import generics
80
82
@@ -234,7 +236,7 b' class IPCompleter(Completer):'
234
236
235 Completer.__init__(self,namespace,global_namespace)
237 Completer.__init__(self,namespace,global_namespace)
236 self.magic_prefix = shell.name+'.magic_'
238 self.magic_prefix = shell.name+'.magic_'
237 self.magic_escape = shell.ESC_MAGIC
239 self.magic_escape = ESC_MAGIC
238 self.readline = readline
240 self.readline = readline
239 delims = self.readline.get_completer_delims()
241 delims = self.readline.get_completer_delims()
240 delims = delims.replace(self.magic_escape,'')
242 delims = delims.replace(self.magic_escape,'')
@@ -301,5 +301,4 b' class Component(HasTraitlets):'
301 self._children.append(child)
301 self._children.append(child)
302
302
303 def __repr__(self):
303 def __repr__(self):
304 return "<%s('%s')>" % (self.__class__.__name__, "DummyName")
304 return "<%s('%s')>" % (self.__class__.__name__, self.name)
305 # return "<Component('%s')>" % self.name
@@ -24,6 +24,8 b' import sys'
24
24
25 from IPython.core.component import Component
25 from IPython.core.component import Component
26
26
27 from IPython.utils.autoattr import auto_attr
28
27 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
28 # Classes and functions
30 # Classes and functions
29 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
@@ -42,6 +44,14 b' class DisplayTrap(Component):'
42 self.hook = hook
44 self.hook = hook
43 self.old_hook = None
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 def __enter__(self):
55 def __enter__(self):
46 self.set()
56 self.set()
47 return self
57 return self
@@ -49,10 +49,12 b' from IPython.core.logger import Logger'
49 from IPython.core.magic import Magic
49 from IPython.core.magic import Magic
50 from IPython.core.prompts import CachedOutput
50 from IPython.core.prompts import CachedOutput
51 from IPython.core.page import page
51 from IPython.core.page import page
52 from IPython.core.prefilter import PrefilterManager
52 from IPython.core.component import Component
53 from IPython.core.component import Component
53 from IPython.core.oldusersetup import user_setup
54 from IPython.core.oldusersetup import user_setup
54 from IPython.core.usage import interactive_usage, default_banner
55 from IPython.core.usage import interactive_usage, default_banner
55 from IPython.core.error import TryNext, UsageError
56 from IPython.core.error import TryNext, UsageError
57 from IPython.core.splitinput import split_user_input
56
58
57 from IPython.extensions import pickleshare
59 from IPython.extensions import pickleshare
58 from IPython.external.Itpl import ItplNS
60 from IPython.external.Itpl import ItplNS
@@ -63,8 +65,8 b' from IPython.utils.genutils import *'
63 from IPython.utils.strdispatch import StrDispatch
65 from IPython.utils.strdispatch import StrDispatch
64 from IPython.utils.platutils import toggle_set_term_title, set_term_title
66 from IPython.utils.platutils import toggle_set_term_title, set_term_title
65
67
66 from IPython.utils import growl
68 # from IPython.utils import growl
67 growl.start("IPython")
69 # growl.start("IPython")
68
70
69 from IPython.utils.traitlets import (
71 from IPython.utils.traitlets import (
70 Int, Float, Str, CBool, CaselessStrEnum, Enum, List, Unicode
72 Int, Float, Str, CBool, CaselessStrEnum, Enum, List, Unicode
@@ -212,7 +214,6 b' class InteractiveShell(Component, Magic):'
212 logstart = CBool(False, config_key='LOGSTART')
214 logstart = CBool(False, config_key='LOGSTART')
213 logfile = Str('', config_key='LOGFILE')
215 logfile = Str('', config_key='LOGFILE')
214 logplay = Str('', config_key='LOGPLAY')
216 logplay = Str('', config_key='LOGPLAY')
215 multi_line_specials = CBool(True, config_key='MULTI_LINE_SPECIALS')
216 object_info_string_level = Enum((0,1,2), default_value=0,
217 object_info_string_level = Enum((0,1,2), default_value=0,
217 config_keys='OBJECT_INFO_STRING_LEVEL')
218 config_keys='OBJECT_INFO_STRING_LEVEL')
218 pager = Str('less', config_key='PAGER')
219 pager = Str('less', config_key='PAGER')
@@ -297,7 +298,7 b' class InteractiveShell(Component, Magic):'
297
298
298 self.init_history()
299 self.init_history()
299 self.init_encoding()
300 self.init_encoding()
300 self.init_handlers()
301 self.init_prefilter()
301
302
302 Magic.__init__(self, self)
303 Magic.__init__(self, self)
303
304
@@ -1595,7 +1596,7 b' class InteractiveShell(Component, Magic):'
1595
1596
1596 args = arg_s.split(' ',1)
1597 args = arg_s.split(' ',1)
1597 magic_name = args[0]
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 try:
1601 try:
1601 magic_args = args[1]
1602 magic_args = args[1]
@@ -1608,7 +1609,6 b' class InteractiveShell(Component, Magic):'
1608 magic_args = self.var_expand(magic_args,1)
1609 magic_args = self.var_expand(magic_args,1)
1609 with nested(self.builtin_trap, self.display_trap):
1610 with nested(self.builtin_trap, self.display_trap):
1610 return fn(magic_args)
1611 return fn(magic_args)
1611 # return result
1612
1612
1613 def define_magic(self, magicname, func):
1613 def define_magic(self, magicname, func):
1614 """Expose own function as magic function for ipython
1614 """Expose own function as magic function for ipython
@@ -1667,58 +1667,6 b' class InteractiveShell(Component, Magic):'
1667 def init_alias(self):
1667 def init_alias(self):
1668 self.alias_manager = AliasManager(self, config=self.config)
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 # Things related to the running of code
1671 # Things related to the running of code
1724 #-------------------------------------------------------------------------
1672 #-------------------------------------------------------------------------
@@ -1774,7 +1722,7 b' class InteractiveShell(Component, Magic):'
1774 This emulates Python's -c option."""
1722 This emulates Python's -c option."""
1775
1723
1776 #sys.argv = ['-c']
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 if not self.interactive:
1726 if not self.interactive:
1779 self.ask_exit()
1727 self.ask_exit()
1780
1728
@@ -1807,7 +1755,7 b' class InteractiveShell(Component, Magic):'
1807 """
1755 """
1808 if line.lstrip() == line:
1756 if line.lstrip() == line:
1809 self.shadowhist.add(line.strip())
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 if line.strip():
1760 if line.strip():
1813 if self.more:
1761 if self.more:
@@ -2154,7 +2102,7 b' class InteractiveShell(Component, Magic):'
2154 if line or more:
2102 if line or more:
2155 # push to raw history, so hist line numbers stay in sync
2103 # push to raw history, so hist line numbers stay in sync
2156 self.input_hist_raw.append("# " + line + "\n")
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 # IPython's runsource returns None if there was an error
2106 # IPython's runsource returns None if there was an error
2159 # compiling the code. This allows us to stop processing right
2107 # compiling the code. This allows us to stop processing right
2160 # away, so the user gets the error message at the right place.
2108 # away, so the user gets the error message at the right place.
@@ -2319,10 +2267,6 b' class InteractiveShell(Component, Magic):'
2319 else:
2267 else:
2320 self.indent_current_nsp = 0
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 def resetbuffer(self):
2270 def resetbuffer(self):
2327 """Reset the input buffer."""
2271 """Reset the input buffer."""
2328 self.buffer[:] = []
2272 self.buffer[:] = []
@@ -2340,7 +2284,8 b' class InteractiveShell(Component, Magic):'
2340 - continue_prompt(False): whether this line is the first one or a
2284 - continue_prompt(False): whether this line is the first one or a
2341 continuation in a sequence of inputs.
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 # Code run by the user may have modified the readline completer state.
2289 # Code run by the user may have modified the readline completer state.
2345 # We must ensure that our completer is back in place.
2290 # We must ensure that our completer is back in place.
2346
2291
@@ -2388,7 +2333,7 b' class InteractiveShell(Component, Magic):'
2388 elif not continue_prompt:
2333 elif not continue_prompt:
2389 self.input_hist_raw.append('\n')
2334 self.input_hist_raw.append('\n')
2390 try:
2335 try:
2391 lineout = self.prefilter(line,continue_prompt)
2336 lineout = self.prefilter_manager.prefilter_lines(line,continue_prompt)
2392 except:
2337 except:
2393 # blanket except, in case a user-defined prefilter crashes, so it
2338 # blanket except, in case a user-defined prefilter crashes, so it
2394 # can't take all of ipython with it.
2339 # can't take all of ipython with it.
@@ -2451,293 +2396,8 b' class InteractiveShell(Component, Magic):'
2451 # Things related to the prefilter
2396 # Things related to the prefilter
2452 #-------------------------------------------------------------------------
2397 #-------------------------------------------------------------------------
2453
2398
2454 def init_handlers(self):
2399 def init_prefilter(self):
2455 # escapes for automatic behavior on the command line
2400 self.prefilter_manager = PrefilterManager(self, config=self.config)
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
2741
2401
2742 #-------------------------------------------------------------------------
2402 #-------------------------------------------------------------------------
2743 # Utilities
2403 # Utilities
@@ -2844,6 +2504,3 b' class InteractiveShell(Component, Magic):'
2844 self.restore_sys_module_state()
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 Prefiltering components.
4 This module is responsible, primarily, for breaking the line up into useful
5
5 pieces and triggering the appropriate handlers in iplib to do the actual
6 Authors:
6 transforming work.
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 import re
28 import re
29 import sys
30
31 from IPython.core.alias import AliasManager
11 from IPython.core.autocall import IPyAutocall
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 class LineInfo(object):
96 class LineInfo(object):
@@ -25,39 +107,39 b' class LineInfo(object):'
25 pre
107 pre
26 The initial esc character or whitespace.
108 The initial esc character or whitespace.
27
109
28 preChar
110 pre_char
29 The escape character(s) in pre or the empty string if there isn't one.
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 always be a single character.
113 always be a single character.
32
114
33 preWhitespace
115 pre_whitespace
34 The leading whitespace from pre if it exists. If there is a preChar,
116 The leading whitespace from pre if it exists. If there is a pre_char,
35 this is just ''.
117 this is just ''.
36
118
37 iFun
119 ifun
38 The 'function part', which is basically the maximal initial sequence
120 The 'function part', which is basically the maximal initial sequence
39 of valid python identifiers and the '.' character. This is what is
121 of valid python identifiers and the '.' character. This is what is
40 checked for alias and magic transformations, used for auto-calling,
122 checked for alias and magic transformations, used for auto-calling,
41 etc.
123 etc.
42
124
43 theRest
125 the_rest
44 Everything else on the line.
126 Everything else on the line.
45 """
127 """
46 def __init__(self, line, continue_prompt):
128 def __init__(self, line, continue_prompt):
47 self.line = line
129 self.line = line
48 self.continue_prompt = continue_prompt
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()
133 self.pre_char = self.pre.strip()
52 if self.preChar:
134 if self.pre_char:
53 self.preWhitespace = '' # No whitespace allowd before esc chars
135 self.pre_whitespace = '' # No whitespace allowd before esc chars
54 else:
136 else:
55 self.preWhitespace = self.pre
137 self.pre_whitespace = self.pre
56
138
57 self._oinfo = None
139 self._oinfo = None
58
140
59 def ofind(self, ip):
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 namespaces for the given IPython InteractiveShell instance.
143 namespaces for the given IPython InteractiveShell instance.
62
144
63 Return a dict with keys: found,obj,ospace,ismagic
145 Return a dict with keys: found,obj,ospace,ismagic
@@ -70,252 +152,626 b' class LineInfo(object):'
70 without worrying about *further* damaging state.
152 without worrying about *further* damaging state.
71 """
153 """
72 if not self._oinfo:
154 if not self._oinfo:
73 self._oinfo = ip._ofind(self.iFun)
155 self._oinfo = ip._ofind(self.ifun)
74 return self._oinfo
156 return self._oinfo
157
75 def __str__(self):
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):
162 #-----------------------------------------------------------------------------
79 """Split user input into pre-char/whitespace, function part and rest.
163 # Main Prefilter manager
164 #-----------------------------------------------------------------------------
80
165
81 Mostly internal to this module, but also used by iplib.expand_aliases,
166
82 which passes in a shell pattern.
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.
176
85
177 multi_line_specials = CBool(True, config_key='MULTI_LINE_SPECIALS')
86 if not pattern:
178
87 pattern = line_split
179 def __init__(self, parent, config=None):
88 match = pattern.match(line)
180 super(PrefilterManager, self).__init__(parent, config=config)
89 if not match:
181 self.init_handlers()
90 #print "match failed for line '%s'" % line
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 try:
216 try:
92 iFun,theRest = line.split(None,1)
217 del self._handlers[name]
93 except ValueError:
218 except KeyError:
94 #print "split failed for line '%s'" % line
219 pass
95 iFun,theRest = line,''
220 for esc_str in esc_strings:
96 pre = re.match('^(\s*)(.*)',line).groups()[0]
221 h = self._esc_handlers.get(esc_str)
97 else:
222 if h is handler:
98 pre,iFun,theRest = match.groups()
223 del self._esc_handlers[esc_str]
99
224
100 # iFun has to be a valid python identifier, so it better be only pure
225 def get_handler_by_name(self, name):
101 # ascii, no unicode:
226 """Get a handler by its name."""
102 try:
227 return self._handlers.get(name)
103 iFun = iFun.encode('ascii')
228
104 except UnicodeEncodeError:
229 def get_handler_by_esc(self, esc_str):
105 theRest = iFun + u' ' + theRest
230 """Get a handler by its escape string."""
106 iFun = u''
231 return self._esc_handlers.get(esc_str)
107
232
108 #print 'line:<%s>' % line # dbg
233 def prefilter_line_info(self, line_info):
109 #print 'pre <%s> iFun <%s> rest <%s>' % (pre,iFun.strip(),theRest) # dbg
234 """Prefilter a line that has been converted to a LineInfo object."""
110 return pre,iFun.strip(),theRest.lstrip()
235 handler = self.find_handler(line_info)
111
236 return handler.handle(line_info)
112
237
113 # RegExp for splitting line contents into pre-char//first word-method//rest.
238 def find_handler(self, line_info):
114 # For clarity, each group in on one line.
239 """Find a handler for the line_info by trying checkers."""
115
240 for checker in self.sorted_checkers:
116 # WARNING: update the regexp if the escapes in iplib are changed, as they
241 handler = checker.check(line_info)
117 # are hardwired in.
242 if handler:
118
243 return handler
119 # Although it's not solely driven by the regex, note that:
244 return self.get_handler_by_name('normal')
120 # ,;/% only trigger if they are the first character on the line
245
121 # ! and !! trigger if they are first char(s) *or* follow an indent
246 def prefilter_line(self, line, continue_prompt):
122 # ? triggers as first or last char.
247 """Prefilter a single input line as text."""
123
248
124 # The three parts of the regex are:
249 # All handlers *must* return a value, even if it's blank ('').
125 # 1) pre: pre_char *or* initial whitespace
250
126 # 2) iFun: first word/method (mix of \w and '.')
251 # Lines are NOT logged here. Handlers should process the line as
127 # 3) theRest: rest of line (separated from iFun by space if non-empty)
252 # needed, update the cache AND log it (so that the input cache array
128 line_split = re.compile(r'^([,;/%?]|!!?|\s*)'
253 # stays synced).
129 r'\s*([\w\.]+)'
254
130 r'(\s+.*$|$)')
255 # growl.notify("_prefilter: ", "line = %s\ncontinue_prompt = %s" % (line, continue_prompt))
131
256
132 shell_line_split = re.compile(r'^(\s*)(\S*\s*)(.*$)')
257 # save the line away in case we crash, so the post-mortem handler can
133
258 # record it
134 def prefilter(line_info, ip):
259 self.shell._last_input_line = line
135 """Call one of the passed-in InteractiveShell's handler preprocessors,
260
136 depending on the form of the line. Return the results, which must be a
261 if not line:
137 value, even if it's a blank ('')."""
262 # Return immediately on purely empty lines, so that if the user
138 # Note: the order of these checks does matter.
263 # previously typed some whitespace that started a continuation
139 for check in [ checkEmacs,
264 # prompt, he can break out of that loop with just an empty line.
140 checkShellEscape,
265 # This is how the default python prompt works.
141 checkIPyAutocall,
266
142 checkMultiLineMagic,
267 # Only return if the accumulated input buffer was just whitespace!
143 checkEscChars,
268 if ''.join(self.shell.buffer).isspace():
144 checkAssignment,
269 self.shell.buffer[:] = []
145 checkAutomagic,
270 return ''
146 checkAlias,
271
147 checkPythonOps,
272 line_info = LineInfo(line, continue_prompt)
148 checkAutocall,
273
149 ]:
274 # the input history needs to track even empty lines
150 handler = check(line_info, ip)
275 stripped = line.strip()
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
178
276
179 def checkIPyAutocall(l_info,ip):
277 handle_normal = self.get_handler_by_name('normal')
180 "Instances of IPyAutocall in user_ns get autocalled immediately"
278 if not stripped:
181 obj = ip.user_ns.get(l_info.iFun, None)
279 if not continue_prompt:
182 if isinstance(obj, IPyAutocall):
280 self.shell.outputcache.prompt_count -= 1
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
200
281
201 def checkEscChars(l_info,ip):
282 return handle_normal(line_info)
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
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):
288 return self.prefilter_line_info(line_info)
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
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):
293 Covers cases where there are multiple lines in the user entry,
230 """If the iFun is magic, and automagic is on, run it. Note: normal,
294 which is the case when the user goes back to a multiline history
231 non-auto magic would already have been triggered via '%' in
295 entry and presses enter.
232 check_esc_chars. This just checks for automagic. Also, before
296 """
233 triggering the magic handler, make sure that there is nothing in the
297 # growl.notify("multiline_prefilter: ", "%s\n%s" % (line, continue_prompt))
234 user namespace which could shadow it."""
298 out = []
235 if not ip.automagic or not hasattr(ip,'magic_'+l_info.iFun):
299 for line in lines.rstrip('\n').split('\n'):
236 return None
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]
305 #-----------------------------------------------------------------------------
243 if isShadowed(head,ip):
306 # Prefilter checkers
244 return None
307 #-----------------------------------------------------------------------------
245
308
246 return ip.handle_magic
247
309
248
310 class PrefilterChecker(Component):
249 def checkAlias(l_info,ip):
311 """Inspect an input line and return a handler for that line."""
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
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):
320 @auto_attr
263 """If the 'rest' of the line begins with a function call or pretty much
321 def shell(self):
264 any python operator, we should simply execute the line (regardless of
322 shell = Component.get_instances(
265 whether or not there's a possible autocall expansion). This avoids
323 root=self.root,
266 spurious (and very confusing) geattr() accesses."""
324 klass='IPython.core.iplib.InteractiveShell'
267 if l_info.theRest and l_info.theRest[0] in '!=()<>,+*/%^&|':
325 )[0]
268 return ip.handle_normal
326 return shell
269 else:
270 return None
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):
332 def check(self, line_info):
274 "Check if the initial word/function is callable and autocall is on."
333 """Inspect line_info and return a handler or None."""
275 if not ip.autocall:
276 return None
334 return None
277
335
278 oinfo = l_info.ofind(ip) # This can mutate state via getattr
336
279 if not oinfo['found']:
337 class EmacsChecker(PrefilterChecker):
280 return None
338
281
339 priority = Int(100)
282 if callable(oinfo['obj']) \
340
283 and (not re_exclude_auto.match(l_info.theRest)) \
341 def check(self, line_info):
284 and re_fun_name.match(l_info.iFun):
342 "Emacs ipython-mode tags certain input lines."
285 #print 'going auto' # dbg
343 if line_info.line.endswith('# PYTHON-MODE'):
286 return ip.handle_auto
344 return self.prefilter_manager.get_handler_by_name('emacs')
287 else:
345 else:
288 #print 'was callable?', callable(l_info.oinfo['obj']) # dbg
346 return None
289 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
415 This allows users to assign to either alias or magic names true python
292 re_fun_name = re.compile(r'[a-zA-Z_]([a-zA-Z0-9_.]*) *$')
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
424 class AutoMagicChecker(PrefilterChecker):
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 ')
305
425
306 # try to catch also methods for stuff in lists/tuples/dicts: off
426 priority = Int(700)
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_.\[\]]*) ?$')
311
427
312 # Handler Check Utilities
428 def check(self, line_info):
313 def isShadowed(identifier,ip):
429 """If the ifun is magic, and automagic is on, run it. Note: normal,
314 """Is the given identifier defined in one of the namespaces which shadow
430 non-auto magic would already have been triggered via '%' in
315 the alias and magic namespaces? Note that an identifier is different
431 check_esc_chars. This just checks for automagic. Also, before
316 than iFun, because it can not contain a '.' character."""
432 triggering the magic handler, make sure that there is nothing in the
317 # This is much safer than calling ofind, which can change state
433 user namespace which could shadow it."""
318 return (identifier in ip.user_ns \
434 if not self.shell.automagic or not hasattr(self.shell,'magic_'+line_info.ifun):
319 or identifier in ip.internal_ns \
435 return None
320 or identifier in ip.ns_table['builtin'])
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