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