##// END OF EJS Templates
First take at cleaning up extensions.
Brian Granger -
Show More
@@ -1,13 +1,2 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """This directory is meant for special-purpose extensions to IPython.
2 """This directory is meant for IPython extensions."""
3
4 This can include things which alter the syntax processing stage (see
5 PhysicalQ_Input for an example of how to do this).
6
7 Any file located here can be called with an 'execfile =' option as
8
9 execfile = extensions/filename.py
10
11 since the IPython directory itself is already part of the search path for
12 files listed as 'execfile ='.
13 """
@@ -1,209 +1,201 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3
3
4 """Magic command interface for interactive parallel work."""
4 """Magic command interface for interactive parallel work."""
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2009 The IPython Development Team
7 # Copyright (C) 2008-2009 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 import new
17 import new
18
18
19 from IPython.core.component import Component
19 from IPython.config.configurable import Configurable
20 from IPython.utils.traitlets import Bool, Any
20 from IPython.utils.traitlets import Bool, Any, Instance
21 from IPython.utils.autoattr import auto_attr
21 from IPython.utils.autoattr import auto_attr
22 from IPython.testing import decorators as testdec
22 from IPython.testing import decorators as testdec
23
23
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25 # Definitions of magic functions for use with IPython
25 # Definitions of magic functions for use with IPython
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27
27
28
28
29 NO_ACTIVE_MULTIENGINE_CLIENT = """
29 NO_ACTIVE_MULTIENGINE_CLIENT = """
30 Use activate() on a MultiEngineClient object to activate it for magics.
30 Use activate() on a MultiEngineClient object to activate it for magics.
31 """
31 """
32
32
33
33
34 class ParalleMagicComponent(Component):
34 class ParalleMagicComponent(Configurable):
35 """A component to manage the %result, %px and %autopx magics."""
35 """A component to manage the %result, %px and %autopx magics."""
36
36
37 active_multiengine_client = Any()
37 active_multiengine_client = Any()
38 verbose = Bool(False, config=True)
38 verbose = Bool(False, config=True)
39 shell = Instance('IPython.core.iplib.InteractiveShell')
39
40
40 def __init__(self, parent, name=None, config=None):
41 def __init__(self, shell, config=None):
41 super(ParalleMagicComponent, self).__init__(parent, name=name, config=config)
42 super(ParalleMagicComponent, self).__init__(config=config)
43 self.shell = shell
42 self._define_magics()
44 self._define_magics()
43 # A flag showing if autopx is activated or not
45 # A flag showing if autopx is activated or not
44 self.autopx = False
46 self.autopx = False
45
47
46 # Access other components like this rather than by a regular attribute.
47 # This won't lookup the InteractiveShell object until it is used and
48 # then it is cached. This is both efficient and couples this class
49 # more loosely to InteractiveShell.
50 @auto_attr
51 def shell(self):
52 return Component.get_instances(
53 root=self.root,
54 klass='IPython.core.iplib.InteractiveShell')[0]
55
56 def _define_magics(self):
48 def _define_magics(self):
57 """Define the magic functions."""
49 """Define the magic functions."""
58 self.shell.define_magic('result', self.magic_result)
50 self.shell.define_magic('result', self.magic_result)
59 self.shell.define_magic('px', self.magic_px)
51 self.shell.define_magic('px', self.magic_px)
60 self.shell.define_magic('autopx', self.magic_autopx)
52 self.shell.define_magic('autopx', self.magic_autopx)
61
53
62 @testdec.skip_doctest
54 @testdec.skip_doctest
63 def magic_result(self, ipself, parameter_s=''):
55 def magic_result(self, ipself, parameter_s=''):
64 """Print the result of command i on all engines..
56 """Print the result of command i on all engines..
65
57
66 To use this a :class:`MultiEngineClient` instance must be created
58 To use this a :class:`MultiEngineClient` instance must be created
67 and then activated by calling its :meth:`activate` method.
59 and then activated by calling its :meth:`activate` method.
68
60
69 Then you can do the following::
61 Then you can do the following::
70
62
71 In [23]: %result
63 In [23]: %result
72 Out[23]:
64 Out[23]:
73 <Results List>
65 <Results List>
74 [0] In [6]: a = 10
66 [0] In [6]: a = 10
75 [1] In [6]: a = 10
67 [1] In [6]: a = 10
76
68
77 In [22]: %result 6
69 In [22]: %result 6
78 Out[22]:
70 Out[22]:
79 <Results List>
71 <Results List>
80 [0] In [6]: a = 10
72 [0] In [6]: a = 10
81 [1] In [6]: a = 10
73 [1] In [6]: a = 10
82 """
74 """
83 if self.active_multiengine_client is None:
75 if self.active_multiengine_client is None:
84 print NO_ACTIVE_MULTIENGINE_CLIENT
76 print NO_ACTIVE_MULTIENGINE_CLIENT
85 return
77 return
86
78
87 try:
79 try:
88 index = int(parameter_s)
80 index = int(parameter_s)
89 except:
81 except:
90 index = None
82 index = None
91 result = self.active_multiengine_client.get_result(index)
83 result = self.active_multiengine_client.get_result(index)
92 return result
84 return result
93
85
94 @testdec.skip_doctest
86 @testdec.skip_doctest
95 def magic_px(self, ipself, parameter_s=''):
87 def magic_px(self, ipself, parameter_s=''):
96 """Executes the given python command in parallel.
88 """Executes the given python command in parallel.
97
89
98 To use this a :class:`MultiEngineClient` instance must be created
90 To use this a :class:`MultiEngineClient` instance must be created
99 and then activated by calling its :meth:`activate` method.
91 and then activated by calling its :meth:`activate` method.
100
92
101 Then you can do the following::
93 Then you can do the following::
102
94
103 In [24]: %px a = 5
95 In [24]: %px a = 5
104 Parallel execution on engines: all
96 Parallel execution on engines: all
105 Out[24]:
97 Out[24]:
106 <Results List>
98 <Results List>
107 [0] In [7]: a = 5
99 [0] In [7]: a = 5
108 [1] In [7]: a = 5
100 [1] In [7]: a = 5
109 """
101 """
110
102
111 if self.active_multiengine_client is None:
103 if self.active_multiengine_client is None:
112 print NO_ACTIVE_MULTIENGINE_CLIENT
104 print NO_ACTIVE_MULTIENGINE_CLIENT
113 return
105 return
114 print "Parallel execution on engines: %s" % self.active_multiengine_client.targets
106 print "Parallel execution on engines: %s" % self.active_multiengine_client.targets
115 result = self.active_multiengine_client.execute(parameter_s)
107 result = self.active_multiengine_client.execute(parameter_s)
116 return result
108 return result
117
109
118 @testdec.skip_doctest
110 @testdec.skip_doctest
119 def magic_autopx(self, ipself, parameter_s=''):
111 def magic_autopx(self, ipself, parameter_s=''):
120 """Toggles auto parallel mode.
112 """Toggles auto parallel mode.
121
113
122 To use this a :class:`MultiEngineClient` instance must be created
114 To use this a :class:`MultiEngineClient` instance must be created
123 and then activated by calling its :meth:`activate` method. Once this
115 and then activated by calling its :meth:`activate` method. Once this
124 is called, all commands typed at the command line are send to
116 is called, all commands typed at the command line are send to
125 the engines to be executed in parallel. To control which engine
117 the engines to be executed in parallel. To control which engine
126 are used, set the ``targets`` attributed of the multiengine client
118 are used, set the ``targets`` attributed of the multiengine client
127 before entering ``%autopx`` mode.
119 before entering ``%autopx`` mode.
128
120
129 Then you can do the following::
121 Then you can do the following::
130
122
131 In [25]: %autopx
123 In [25]: %autopx
132 %autopx to enabled
124 %autopx to enabled
133
125
134 In [26]: a = 10
126 In [26]: a = 10
135 <Results List>
127 <Results List>
136 [0] In [8]: a = 10
128 [0] In [8]: a = 10
137 [1] In [8]: a = 10
129 [1] In [8]: a = 10
138
130
139
131
140 In [27]: %autopx
132 In [27]: %autopx
141 %autopx disabled
133 %autopx disabled
142 """
134 """
143 if self.autopx:
135 if self.autopx:
144 self._disable_autopx()
136 self._disable_autopx()
145 else:
137 else:
146 self._enable_autopx()
138 self._enable_autopx()
147
139
148 def _enable_autopx(self):
140 def _enable_autopx(self):
149 """Enable %autopx mode by saving the original runsource and installing
141 """Enable %autopx mode by saving the original runsource and installing
150 pxrunsource.
142 pxrunsource.
151 """
143 """
152 if self.active_multiengine_client is None:
144 if self.active_multiengine_client is None:
153 print NO_ACTIVE_MULTIENGINE_CLIENT
145 print NO_ACTIVE_MULTIENGINE_CLIENT
154 return
146 return
155
147
156 self._original_runsource = self.shell.runsource
148 self._original_runsource = self.shell.runsource
157 self.shell.runsource = new.instancemethod(
149 self.shell.runsource = new.instancemethod(
158 self.pxrunsource, self.shell, self.shell.__class__
150 self.pxrunsource, self.shell, self.shell.__class__
159 )
151 )
160 self.autopx = True
152 self.autopx = True
161 print "%autopx enabled"
153 print "%autopx enabled"
162
154
163 def _disable_autopx(self):
155 def _disable_autopx(self):
164 """Disable %autopx by restoring the original InteractiveShell.runsource."""
156 """Disable %autopx by restoring the original InteractiveShell.runsource."""
165 if self.autopx:
157 if self.autopx:
166 self.shell.runsource = self._original_runsource
158 self.shell.runsource = self._original_runsource
167 self.autopx = False
159 self.autopx = False
168 print "%autopx disabled"
160 print "%autopx disabled"
169
161
170 def pxrunsource(self, ipself, source, filename="<input>", symbol="single"):
162 def pxrunsource(self, ipself, source, filename="<input>", symbol="single"):
171 """A parallel replacement for InteractiveShell.runsource."""
163 """A parallel replacement for InteractiveShell.runsource."""
172
164
173 try:
165 try:
174 code = ipself.compile(source, filename, symbol)
166 code = ipself.compile(source, filename, symbol)
175 except (OverflowError, SyntaxError, ValueError):
167 except (OverflowError, SyntaxError, ValueError):
176 # Case 1
168 # Case 1
177 ipself.showsyntaxerror(filename)
169 ipself.showsyntaxerror(filename)
178 return None
170 return None
179
171
180 if code is None:
172 if code is None:
181 # Case 2
173 # Case 2
182 return True
174 return True
183
175
184 # Case 3
176 # Case 3
185 # Because autopx is enabled, we now call executeAll or disable autopx if
177 # Because autopx is enabled, we now call executeAll or disable autopx if
186 # %autopx or autopx has been called
178 # %autopx or autopx has been called
187 if 'get_ipython().magic("%autopx' in source or 'get_ipython().magic("autopx' in source:
179 if 'get_ipython().magic("%autopx' in source or 'get_ipython().magic("autopx' in source:
188 self._disable_autopx()
180 self._disable_autopx()
189 return False
181 return False
190 else:
182 else:
191 try:
183 try:
192 result = self.active_multiengine_client.execute(source)
184 result = self.active_multiengine_client.execute(source)
193 except:
185 except:
194 ipself.showtraceback()
186 ipself.showtraceback()
195 else:
187 else:
196 print result.__repr__()
188 print result.__repr__()
197 return False
189 return False
198
190
199
191
200 _loaded = False
192 _loaded = False
201
193
202
194
203 def load_ipython_extension(ip):
195 def load_ipython_extension(ip):
204 """Load the extension in IPython."""
196 """Load the extension in IPython."""
205 global _loaded
197 global _loaded
206 if not _loaded:
198 if not _loaded:
207 prd = ParalleMagicComponent(ip, name='parallel_magic')
199 prd = ParalleMagicComponent(ip, config=ip.config)
208 _loaded = True
200 _loaded = True
209
201
@@ -1,166 +1,158 b''
1 """Use pretty.py for configurable pretty-printing.
1 """Use pretty.py for configurable pretty-printing.
2
2
3 To enable this extension in your configuration
3 To enable this extension in your configuration
4 file, add the following to :file:`ipython_config.py`::
4 file, add the following to :file:`ipython_config.py`::
5
5
6 c.Global.extensions = ['IPython.extensions.pretty']
6 c.Global.extensions = ['IPython.extensions.pretty']
7 def dict_pprinter(obj, p, cycle):
7 def dict_pprinter(obj, p, cycle):
8 return p.text("<dict>")
8 return p.text("<dict>")
9 c.PrettyResultDisplay.verbose = True
9 c.PrettyResultDisplay.verbose = True
10 c.PrettyResultDisplay.defaults_for_type = [
10 c.PrettyResultDisplay.defaults_for_type = [
11 (dict, dict_pprinter)
11 (dict, dict_pprinter)
12 ]
12 ]
13 c.PrettyResultDisplay.defaults_for_type_by_name = [
13 c.PrettyResultDisplay.defaults_for_type_by_name = [
14 ('numpy', 'dtype', 'IPython.extensions.pretty.dtype_pprinter')
14 ('numpy', 'dtype', 'IPython.extensions.pretty.dtype_pprinter')
15 ]
15 ]
16
16
17 This extension can also be loaded by using the ``%load_ext`` magic::
17 This extension can also be loaded by using the ``%load_ext`` magic::
18
18
19 %load_ext IPython.extensions.pretty
19 %load_ext IPython.extensions.pretty
20
20
21 If this extension is enabled, you can always add additional pretty printers
21 If this extension is enabled, you can always add additional pretty printers
22 by doing::
22 by doing::
23
23
24 ip = get_ipython()
24 ip = get_ipython()
25 prd = ip.get_component('pretty_result_display')
25 prd = ip.get_component('pretty_result_display')
26 import numpy
26 import numpy
27 from IPython.extensions.pretty import dtype_pprinter
27 from IPython.extensions.pretty import dtype_pprinter
28 prd.for_type(numpy.dtype, dtype_pprinter)
28 prd.for_type(numpy.dtype, dtype_pprinter)
29
29
30 # If you don't want to have numpy imported until it needs to be:
30 # If you don't want to have numpy imported until it needs to be:
31 prd.for_type_by_name('numpy', 'dtype', dtype_pprinter)
31 prd.for_type_by_name('numpy', 'dtype', dtype_pprinter)
32 """
32 """
33
33
34 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
35 # Imports
35 # Imports
36 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
37
37
38 from IPython.core.error import TryNext
38 from IPython.core.error import TryNext
39 from IPython.external import pretty
39 from IPython.external import pretty
40 from IPython.core.component import Component
40 from IPython.config.configurable import Configurable
41 from IPython.utils.traitlets import Bool, List
41 from IPython.utils.traitlets import Bool, List, Instance
42 from IPython.utils.io import Term
42 from IPython.utils.io import Term
43 from IPython.utils.autoattr import auto_attr
43 from IPython.utils.autoattr import auto_attr
44 from IPython.utils.importstring import import_item
44 from IPython.utils.importstring import import_item
45
45
46 #-----------------------------------------------------------------------------
46 #-----------------------------------------------------------------------------
47 # Code
47 # Code
48 #-----------------------------------------------------------------------------
48 #-----------------------------------------------------------------------------
49
49
50
50
51 _loaded = False
51 _loaded = False
52
52
53
53
54 class PrettyResultDisplay(Component):
54 class PrettyResultDisplay(Configurable):
55 """A component for pretty printing on steroids."""
55 """A component for pretty printing on steroids."""
56
56
57 verbose = Bool(False, config=True)
57 verbose = Bool(False, config=True)
58 shell = Instance('IPython.core.iplib.InteractiveShell')
58
59
59 # A list of (type, func_name), like
60 # A list of (type, func_name), like
60 # [(dict, 'my_dict_printer')]
61 # [(dict, 'my_dict_printer')]
61 # The final argument can also be a callable
62 # The final argument can also be a callable
62 defaults_for_type = List(default_value=[], config=True)
63 defaults_for_type = List(default_value=[], config=True)
63
64
64 # A list of (module_name, type_name, func_name), like
65 # A list of (module_name, type_name, func_name), like
65 # [('numpy', 'dtype', 'IPython.extensions.pretty.dtype_pprinter')]
66 # [('numpy', 'dtype', 'IPython.extensions.pretty.dtype_pprinter')]
66 # The final argument can also be a callable
67 # The final argument can also be a callable
67 defaults_for_type_by_name = List(default_value=[], config=True)
68 defaults_for_type_by_name = List(default_value=[], config=True)
68
69
69 def __init__(self, parent, name=None, config=None):
70 def __init__(self, shell, config=None):
70 super(PrettyResultDisplay, self).__init__(parent, name=name, config=config)
71 super(PrettyResultDisplay, self).__init__(config=config)
72 self.shell = shell
71 self._setup_defaults()
73 self._setup_defaults()
72
74
73 def _setup_defaults(self):
75 def _setup_defaults(self):
74 """Initialize the default pretty printers."""
76 """Initialize the default pretty printers."""
75 for typ, func_name in self.defaults_for_type:
77 for typ, func_name in self.defaults_for_type:
76 func = self._resolve_func_name(func_name)
78 func = self._resolve_func_name(func_name)
77 self.for_type(typ, func)
79 self.for_type(typ, func)
78 for type_module, type_name, func_name in self.defaults_for_type_by_name:
80 for type_module, type_name, func_name in self.defaults_for_type_by_name:
79 func = self._resolve_func_name(func_name)
81 func = self._resolve_func_name(func_name)
80 self.for_type_by_name(type_module, type_name, func)
82 self.for_type_by_name(type_module, type_name, func)
81
83
82 def _resolve_func_name(self, func_name):
84 def _resolve_func_name(self, func_name):
83 if callable(func_name):
85 if callable(func_name):
84 return func_name
86 return func_name
85 elif isinstance(func_name, basestring):
87 elif isinstance(func_name, basestring):
86 return import_item(func_name)
88 return import_item(func_name)
87 else:
89 else:
88 raise TypeError('func_name must be a str or callable, got: %r' % func_name)
90 raise TypeError('func_name must be a str or callable, got: %r' % func_name)
89
91
90 # Access other components like this rather than by a regular attribute.
91 # This won't lookup the InteractiveShell object until it is used and
92 # then it is cached. This is both efficient and couples this class
93 # more loosely to InteractiveShell.
94 @auto_attr
95 def shell(self):
96 return Component.get_instances(
97 root=self.root,
98 klass='IPython.core.iplib.InteractiveShell')[0]
99
100 def __call__(self, otherself, arg):
92 def __call__(self, otherself, arg):
101 """Uber-pretty-printing display hook.
93 """Uber-pretty-printing display hook.
102
94
103 Called for displaying the result to the user.
95 Called for displaying the result to the user.
104 """
96 """
105
97
106 if self.shell.pprint:
98 if self.shell.pprint:
107 out = pretty.pretty(arg, verbose=self.verbose)
99 out = pretty.pretty(arg, verbose=self.verbose)
108 if '\n' in out:
100 if '\n' in out:
109 # So that multi-line strings line up with the left column of
101 # So that multi-line strings line up with the left column of
110 # the screen, instead of having the output prompt mess up
102 # the screen, instead of having the output prompt mess up
111 # their first line.
103 # their first line.
112 Term.cout.write('\n')
104 Term.cout.write('\n')
113 print >>Term.cout, out
105 print >>Term.cout, out
114 else:
106 else:
115 raise TryNext
107 raise TryNext
116
108
117 def for_type(self, typ, func):
109 def for_type(self, typ, func):
118 """Add a pretty printer for a type."""
110 """Add a pretty printer for a type."""
119 return pretty.for_type(typ, func)
111 return pretty.for_type(typ, func)
120
112
121 def for_type_by_name(self, type_module, type_name, func):
113 def for_type_by_name(self, type_module, type_name, func):
122 """Add a pretty printer for a type by its name and module name."""
114 """Add a pretty printer for a type by its name and module name."""
123 return pretty.for_type_by_name(type_module, type_name, func)
115 return pretty.for_type_by_name(type_module, type_name, func)
124
116
125
117
126 #-----------------------------------------------------------------------------
118 #-----------------------------------------------------------------------------
127 # Initialization code for the extension
119 # Initialization code for the extension
128 #-----------------------------------------------------------------------------
120 #-----------------------------------------------------------------------------
129
121
130
122
131 def load_ipython_extension(ip):
123 def load_ipython_extension(ip):
132 """Load the extension in IPython as a hook."""
124 """Load the extension in IPython as a hook."""
133 global _loaded
125 global _loaded
134 if not _loaded:
126 if not _loaded:
135 prd = PrettyResultDisplay(ip, name='pretty_result_display')
127 prd = PrettyResultDisplay(ip, config=ip.config)
136 ip.set_hook('result_display', prd, priority=99)
128 ip.set_hook('result_display', prd, priority=99)
137 _loaded = True
129 _loaded = True
138 return prd
130 return prd
139
131
140 def unload_ipython_extension(ip):
132 def unload_ipython_extension(ip):
141 """Unload the extension."""
133 """Unload the extension."""
142 # The hook system does not have a way to remove a hook so this is a pass
134 # The hook system does not have a way to remove a hook so this is a pass
143 pass
135 pass
144
136
145
137
146 #-----------------------------------------------------------------------------
138 #-----------------------------------------------------------------------------
147 # Example pretty printers
139 # Example pretty printers
148 #-----------------------------------------------------------------------------
140 #-----------------------------------------------------------------------------
149
141
150
142
151 def dtype_pprinter(obj, p, cycle):
143 def dtype_pprinter(obj, p, cycle):
152 """ A pretty-printer for numpy dtype objects.
144 """ A pretty-printer for numpy dtype objects.
153 """
145 """
154 if cycle:
146 if cycle:
155 return p.text('dtype(...)')
147 return p.text('dtype(...)')
156 if hasattr(obj, 'fields'):
148 if hasattr(obj, 'fields'):
157 if obj.fields is None:
149 if obj.fields is None:
158 p.text(repr(obj))
150 p.text(repr(obj))
159 else:
151 else:
160 p.begin_group(7, 'dtype([')
152 p.begin_group(7, 'dtype([')
161 for i, field in enumerate(obj.descr):
153 for i, field in enumerate(obj.descr):
162 if i > 0:
154 if i > 0:
163 p.text(',')
155 p.text(',')
164 p.breakable()
156 p.breakable()
165 p.pretty(field)
157 p.pretty(field)
166 p.end_group(7, '])')
158 p.end_group(7, '])')
General Comments 0
You need to be logged in to leave comments. Login now