##// 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,6 +74,8 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 from IPython.core.prefilter import ESC_MAGIC
78
77 import IPython.utils.rlineimpl as readline
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
@@ -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, (816 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)
77
160
78 def splitUserInput(line, pattern=None):
79 """Split user input into pre-char/whitespace, function part and rest.
80
161
81 Mostly internal to this module, but also used by iplib.expand_aliases,
162 #-----------------------------------------------------------------------------
82 which passes in a shell pattern.
163 # Main Prefilter manager
83 """
164 #-----------------------------------------------------------------------------
84 # It seems to me that the shell splitting should be a separate method.
85
165
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
91 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
166
100 # iFun has to be a valid python identifier, so it better be only pure
167 class PrefilterManager(Component):
101 # ascii, no unicode:
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.
175 """
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."""
102 try:
216 try:
103 iFun = iFun.encode('ascii')
217 del self._handlers[name]
104 except UnicodeEncodeError:
218 except KeyError:
105 theRest = iFun + u' ' + theRest
219 pass
106 iFun = u''
220 for esc_str in esc_strings:
107
221 h = self._esc_handlers.get(esc_str)
108 #print 'line:<%s>' % line # dbg
222 if h is handler:
109 #print 'pre <%s> iFun <%s> rest <%s>' % (pre,iFun.strip(),theRest) # dbg
223 del self._esc_handlers[esc_str]
110 return pre,iFun.strip(),theRest.lstrip()
224
111
225 def get_handler_by_name(self, name):
112
226 """Get a handler by its name."""
113 # RegExp for splitting line contents into pre-char//first word-method//rest.
227 return self._handlers.get(name)
114 # For clarity, each group in on one line.
228
115
229 def get_handler_by_esc(self, esc_str):
116 # WARNING: update the regexp if the escapes in iplib are changed, as they
230 """Get a handler by its escape string."""
117 # are hardwired in.
231 return self._esc_handlers.get(esc_str)
118
232
119 # Although it's not solely driven by the regex, note that:
233 def prefilter_line_info(self, line_info):
120 # ,;/% only trigger if they are the first character on the line
234 """Prefilter a line that has been converted to a LineInfo object."""
121 # ! and !! trigger if they are first char(s) *or* follow an indent
235 handler = self.find_handler(line_info)
122 # ? triggers as first or last char.
236 return handler.handle(line_info)
123
237
124 # The three parts of the regex are:
238 def find_handler(self, line_info):
125 # 1) pre: pre_char *or* initial whitespace
239 """Find a handler for the line_info by trying checkers."""
126 # 2) iFun: first word/method (mix of \w and '.')
240 for checker in self.sorted_checkers:
127 # 3) theRest: rest of line (separated from iFun by space if non-empty)
241 handler = checker.check(line_info)
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:
242 if handler:
152 return handler(line_info)
243 return handler
244 return self.get_handler_by_name('normal')
153
245
154 return ip.handle_normal(line_info)
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()
276
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
281
282 return handle_normal(line_info)
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)
287
288 return self.prefilter_line_info(line_info)
289
290 def prefilter_lines(self, lines, continue_prompt):
291 """Prefilter multiple input lines of text.
292
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)
303
304
305 #-----------------------------------------------------------------------------
306 # Prefilter checkers
307 #-----------------------------------------------------------------------------
308
309
310 class PrefilterChecker(Component):
311 """Inspect an input line and return a handler for that line."""
312
313 priority = Int(100)
314 shell = Any
315 prefilter_manager = Any
316
317 def __init__(self, parent, config=None):
318 super(PrefilterChecker, self).__init__(parent, config=config)
319
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
327
328 @auto_attr
329 def prefilter_manager(self):
330 return PrefilterManager.get_instances(root=self.root)[0]
331
332 def check(self, line_info):
333 """Inspect line_info and return a handler or None."""
334 return None
155
335
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
336
168 def checkShellEscape(l_info,ip):
337 class EmacsChecker(PrefilterChecker):
169 if l_info.line.lstrip().startswith(ip.ESC_SHELL):
170 return ip.handle_shell_escape
171
338
172 def checkEmacs(l_info,ip):
339 priority = Int(100)
340
341 def check(self, line_info):
173 "Emacs ipython-mode tags certain input lines."
342 "Emacs ipython-mode tags certain input lines."
174 if l_info.line.endswith('# PYTHON-MODE'):
343 if line_info.line.endswith('# PYTHON-MODE'):
175 return ip.handle_emacs
344 return self.prefilter_manager.get_handler_by_name('emacs')
176 else:
345 else:
177 return None
346 return None
178
347
179 def checkIPyAutocall(l_info,ip):
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):
180 "Instances of IPyAutocall in user_ns get autocalled immediately"
363 "Instances of IPyAutocall in user_ns get autocalled immediately"
181 obj = ip.user_ns.get(l_info.iFun, None)
364 obj = self.shell.user_ns.get(line_info.ifun, None)
182 if isinstance(obj, IPyAutocall):
365 if isinstance(obj, IPyAutocall):
183 obj.set_ip(ip)
366 obj.set_ip(self.shell)
184 return ip.handle_auto
367 return self.prefilter_manager.get_handler_by_name('auto')
185 else:
368 else:
186 return None
369 return None
187
370
188
371
189 def checkMultiLineMagic(l_info,ip):
372 class MultiLineMagicChecker(PrefilterChecker):
373
374 priority = Int(400)
375
376 def check(self, line_info):
190 "Allow ! and !! in multi-line statements if multi_line_specials is on"
377 "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
378 # 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
379 # ifun and *not* the pre_char. Also note that the below test matches
193 # both ! and !!.
380 # both ! and !!.
194 if l_info.continue_prompt \
381 if line_info.continue_prompt \
195 and ip.multi_line_specials:
382 and self.prefilter_manager.multi_line_specials:
196 if l_info.iFun.startswith(ip.ESC_MAGIC):
383 if line_info.ifun.startswith(ESC_MAGIC):
197 return ip.handle_magic
384 return self.prefilter_manager.get_handler_by_name('magic')
198 else:
385 else:
199 return None
386 return None
200
387
201 def checkEscChars(l_info,ip):
388
389 class EscCharsChecker(PrefilterChecker):
390
391 priority = Int(500)
392
393 def check(self, line_info):
202 """Check for escape character and return either a handler to handle it,
394 """Check for escape character and return either a handler to handle it,
203 or None if there is no escape char."""
395 or None if there is no escape char."""
204 if l_info.line[-1] == ip.ESC_HELP \
396 if line_info.line[-1] == ESC_HELP \
205 and l_info.preChar != ip.ESC_SHELL \
397 and line_info.pre_char != ESC_SHELL \
206 and l_info.preChar != ip.ESC_SH_CAP:
398 and line_info.pre_char != ESC_SH_CAP:
207 # the ? can be at the end, but *not* for either kind of shell escape,
399 # 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
400 # because a ? can be a vaild final char in a shell cmd
209 return ip.handle_help
401 return self.prefilter_manager.get_handler_by_name('help')
210 elif l_info.preChar in ip.esc_handlers:
211 return ip.esc_handlers[l_info.preChar]
212 else:
402 else:
213 return None
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
214
406
407 class AssignmentChecker(PrefilterChecker):
215
408
216 def checkAssignment(l_info,ip):
409 priority = Int(600)
410
411 def check(self, line_info):
217 """Check to see if user is assigning to a var for the first time, in
412 """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.
413 which case we want to avoid any sort of automagic / autocall games.
219
414
220 This allows users to assign to either alias or magic names true python
415 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
416 variables (the magic/alias systems always take second seat to true
222 python code). E.g. ls='hi', or ls,that=1,2"""
417 python code). E.g. ls='hi', or ls,that=1,2"""
223 if l_info.theRest and l_info.theRest[0] in '=,':
418 if line_info.the_rest and line_info.the_rest[0] in '=,':
224 return ip.handle_normal
419 return self.prefilter_manager.get_handler_by_name('normal')
225 else:
420 else:
226 return None
421 return None
227
422
228
423
229 def checkAutomagic(l_info,ip):
424 class AutoMagicChecker(PrefilterChecker):
230 """If the iFun is magic, and automagic is on, run it. Note: normal,
425
426 priority = Int(700)
427
428 def check(self, line_info):
429 """If the ifun is magic, and automagic is on, run it. Note: normal,
231 non-auto magic would already have been triggered via '%' in
430 non-auto magic would already have been triggered via '%' in
232 check_esc_chars. This just checks for automagic. Also, before
431 check_esc_chars. This just checks for automagic. Also, before
233 triggering the magic handler, make sure that there is nothing in the
432 triggering the magic handler, make sure that there is nothing in the
234 user namespace which could shadow it."""
433 user namespace which could shadow it."""
235 if not ip.automagic or not hasattr(ip,'magic_'+l_info.iFun):
434 if not self.shell.automagic or not hasattr(self.shell,'magic_'+line_info.ifun):
236 return None
435 return None
237
436
238 # We have a likely magic method. Make sure we should actually call it.
437 # 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:
438 if line_info.continue_prompt and not self.shell.multi_line_specials:
240 return None
439 return None
241
440
242 head = l_info.iFun.split('.',1)[0]
441 head = line_info.ifun.split('.',1)[0]
243 if isShadowed(head,ip):
442 if is_shadowed(head, self.shell):
244 return None
443 return None
245
444
246 return ip.handle_magic
445 return self.prefilter_manager.get_handler_by_name('magic')
446
447
448 class AliasChecker(PrefilterChecker):
247
449
450 priority = Int(800)
248
451
249 def checkAlias(l_info,ip):
452 @auto_attr
453 def alias_manager(self):
454 return AliasManager.get_instances(root=self.root)[0]
455
456 def check(self, line_info):
250 "Check if the initital identifier on the line is an alias."
457 "Check if the initital identifier on the line is an alias."
251 # Note: aliases can not contain '.'
458 # Note: aliases can not contain '.'
252 head = l_info.iFun.split('.',1)[0]
459 head = line_info.ifun.split('.',1)[0]
253
460 if line_info.ifun not in self.alias_manager \
254 if l_info.iFun not in ip.alias_manager \
461 or head not in self.alias_manager \
255 or head not in ip.alias_manager \
462 or is_shadowed(head, self.shell):
256 or isShadowed(head,ip):
257 return None
463 return None
258
464
259 return ip.handle_alias
465 return self.prefilter_manager.get_handler_by_name('alias')
466
260
467
468 class PythonOpsChecker(PrefilterChecker):
261
469
262 def checkPythonOps(l_info,ip):
470 priority = Int(900)
471
472 def check(self, line_info):
263 """If the 'rest' of the line begins with a function call or pretty much
473 """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
474 any python operator, we should simply execute the line (regardless of
265 whether or not there's a possible autocall expansion). This avoids
475 whether or not there's a possible autocall expansion). This avoids
266 spurious (and very confusing) geattr() accesses."""
476 spurious (and very confusing) geattr() accesses."""
267 if l_info.theRest and l_info.theRest[0] in '!=()<>,+*/%^&|':
477 if line_info.the_rest and line_info.the_rest[0] in '!=()<>,+*/%^&|':
268 return ip.handle_normal
478 return self.prefilter_manager.get_handler_by_name('normal')
269 else:
479 else:
270 return None
480 return None
271
481
272
482
273 def checkAutocall(l_info,ip):
483 class AutocallChecker(PrefilterChecker):
484
485 priority = Int(1000)
486
487 def check(self, line_info):
274 "Check if the initial word/function is callable and autocall is on."
488 "Check if the initial word/function is callable and autocall is on."
275 if not ip.autocall:
489 if not self.shell.autocall:
276 return None
490 return None
277
491
278 oinfo = l_info.ofind(ip) # This can mutate state via getattr
492 oinfo = line_info.ofind(self.shell) # This can mutate state via getattr
279 if not oinfo['found']:
493 if not oinfo['found']:
280 return None
494 return None
281
495
282 if callable(oinfo['obj']) \
496 if callable(oinfo['obj']) \
283 and (not re_exclude_auto.match(l_info.theRest)) \
497 and (not re_exclude_auto.match(line_info.the_rest)) \
284 and re_fun_name.match(l_info.iFun):
498 and re_fun_name.match(line_info.ifun):
285 #print 'going auto' # dbg
499 return self.prefilter_manager.get_handler_by_name('auto')
286 return ip.handle_auto
287 else:
500 else:
288 #print 'was callable?', callable(l_info.oinfo['obj']) # dbg
289 return None
501 return None
290
502
291 # RegExp to identify potential function names
292 re_fun_name = re.compile(r'[a-zA-Z_]([a-zA-Z0-9_.]*) *$')
293
503
294 # RegExp to exclude strings with this start from autocalling. In
504 #-----------------------------------------------------------------------------
295 # particular, all binary operators should be excluded, so that if foo is
505 # Prefilter handlers
296 # callable, foo OP bar doesn't become foo(OP bar), which is invalid. The
506 #-----------------------------------------------------------------------------
297 # characters '!=()' don't need to be checked for, as the checkPythonChars
507
298 # routine explicitely does so, to catch direct calls and rebindings of
508
299 # existing names.
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)
300
677
301 # Warning: the '-' HAS TO BE AT THE END of the first group, otherwise
678 if auto_rewrite:
302 # it affects the rest of the group in square brackets.
679 rw = self.shell.outputcache.prompt1.auto_rewrite() + newcmd
303 re_exclude_auto = re.compile(r'^[,&^\|\*/\+-]'
304 r'|^is |^not |^in |^and |^or ')
305
680
306 # try to catch also methods for stuff in lists/tuples/dicts: off
681 try:
307 # (experimental). For this to work, the line_split regexp would need
682 # plain ascii works better w/ pyreadline, on some machines, so
308 # to be modified so it wouldn't break things at '['. That line is
683 # we use it and only print uncolored rewrite if we have unicode
309 # nasty enough that I shouldn't change it until I can test it _well_.
684 rw = str(rw)
310 #self.re_fun_name = re.compile (r'[a-zA-Z_]([a-zA-Z0-9_.\[\]]*) ?$')
685 print >>Term.cout, rw
686 except UnicodeEncodeError:
687 print "-------------->" + newcmd
311
688
312 # Handler Check Utilities
689 # log what is now valid Python, not the actual user input (without the
313 def isShadowed(identifier,ip):
690 # final newline)
314 """Is the given identifier defined in one of the namespaces which shadow
691 self.shell.log(line,newcmd,continue_prompt)
315 the alias and magic namespaces? Note that an identifier is different
692 return newcmd
316 than iFun, because it can not contain a '.' character."""
693
317 # This is much safer than calling ofind, which can change state
694
318 return (identifier in ip.user_ns \
695 class HelpHandler(PrefilterHandler):
319 or identifier in ip.internal_ns \
696
320 or identifier in ip.ns_table['builtin'])
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