##// END OF EJS Templates
Merge pull request #4209 from davclark/magic-doc-fixes...
Thomas Kluyver -
r12548:23b8d0b2 merge
parent child Browse files
Show More
@@ -1,325 +1,334 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 =====================
4 4 Cython related magics
5 5 =====================
6 6
7 Magic command interface for interactive work with Cython
8
9 .. note::
10
11 The ``Cython`` package needs to be installed separately. It
12 can be obtained using ``easy_install`` or ``pip``.
13
7 14 Usage
8 15 =====
9 16
17 To enable the magics below, execute ``%load_ext cythonmagic``.
18
10 19 ``%%cython``
11 20
12 21 {CYTHON_DOC}
13 22
14 23 ``%%cython_inline``
15 24
16 25 {CYTHON_INLINE_DOC}
17 26
18 27 ``%%cython_pyximport``
19 28
20 29 {CYTHON_PYXIMPORT_DOC}
21 30
22 31 Author:
23 32 * Brian Granger
24 33
25 34 Parts of this code were taken from Cython.inline.
26 35 """
27 36 #-----------------------------------------------------------------------------
28 37 # Copyright (C) 2010-2011, IPython Development Team.
29 38 #
30 39 # Distributed under the terms of the Modified BSD License.
31 40 #
32 41 # The full license is in the file COPYING.txt, distributed with this software.
33 42 #-----------------------------------------------------------------------------
34 43
35 44 from __future__ import print_function
36 45
37 46 import imp
38 47 import io
39 48 import os
40 49 import re
41 50 import sys
42 51 import time
43 52
44 53 try:
45 54 reload
46 55 except NameError: # Python 3
47 56 from imp import reload
48 57
49 58 try:
50 59 import hashlib
51 60 except ImportError:
52 61 import md5 as hashlib
53 62
54 63 from distutils.core import Distribution, Extension
55 64 from distutils.command.build_ext import build_ext
56 65
57 66 from IPython.core import display
58 67 from IPython.core import magic_arguments
59 68 from IPython.core.magic import Magics, magics_class, cell_magic
60 69 from IPython.utils import py3compat
61 70 from IPython.utils.path import get_ipython_cache_dir
62 71
63 72 import Cython
64 73 from Cython.Compiler.Errors import CompileError
65 74 from Cython.Build.Dependencies import cythonize
66 75
67 76
68 77 @magics_class
69 78 class CythonMagics(Magics):
70 79
71 80 def __init__(self, shell):
72 81 super(CythonMagics,self).__init__(shell)
73 82 self._reloads = {}
74 83 self._code_cache = {}
75 84
76 85 def _import_all(self, module):
77 86 for k,v in module.__dict__.items():
78 87 if not k.startswith('__'):
79 88 self.shell.push({k:v})
80 89
81 90 @cell_magic
82 91 def cython_inline(self, line, cell):
83 92 """Compile and run a Cython code cell using Cython.inline.
84 93
85 94 This magic simply passes the body of the cell to Cython.inline
86 95 and returns the result. If the variables `a` and `b` are defined
87 96 in the user's namespace, here is a simple example that returns
88 97 their sum::
89 98
90 99 %%cython_inline
91 100 return a+b
92 101
93 102 For most purposes, we recommend the usage of the `%%cython` magic.
94 103 """
95 104 locs = self.shell.user_global_ns
96 105 globs = self.shell.user_ns
97 106 return Cython.inline(cell, locals=locs, globals=globs)
98 107
99 108 @cell_magic
100 109 def cython_pyximport(self, line, cell):
101 110 """Compile and import a Cython code cell using pyximport.
102 111
103 112 The contents of the cell are written to a `.pyx` file in the current
104 113 working directory, which is then imported using `pyximport`. This
105 114 magic requires a module name to be passed::
106 115
107 116 %%cython_pyximport modulename
108 117 def f(x):
109 118 return 2.0*x
110 119
111 120 The compiled module is then imported and all of its symbols are
112 121 injected into the user's namespace. For most purposes, we recommend
113 122 the usage of the `%%cython` magic.
114 123 """
115 124 module_name = line.strip()
116 125 if not module_name:
117 126 raise ValueError('module name must be given')
118 127 fname = module_name + '.pyx'
119 128 with io.open(fname, 'w', encoding='utf-8') as f:
120 129 f.write(cell)
121 130 if 'pyximport' not in sys.modules:
122 131 import pyximport
123 132 pyximport.install(reload_support=True)
124 133 if module_name in self._reloads:
125 134 module = self._reloads[module_name]
126 135 reload(module)
127 136 else:
128 137 __import__(module_name)
129 138 module = sys.modules[module_name]
130 139 self._reloads[module_name] = module
131 140 self._import_all(module)
132 141
133 142 @magic_arguments.magic_arguments()
134 143 @magic_arguments.argument(
135 144 '-c', '--compile-args', action='append', default=[],
136 145 help="Extra flags to pass to compiler via the `extra_compile_args` "
137 146 "Extension flag (can be specified multiple times)."
138 147 )
139 148 @magic_arguments.argument(
140 149 '--link-args', action='append', default=[],
141 150 help="Extra flags to pass to linker via the `extra_link_args` "
142 151 "Extension flag (can be specified multiple times)."
143 152 )
144 153 @magic_arguments.argument(
145 154 '-l', '--lib', action='append', default=[],
146 155 help="Add a library to link the extension against (can be specified "
147 156 "multiple times)."
148 157 )
149 158 @magic_arguments.argument(
150 159 '-L', dest='library_dirs', metavar='dir', action='append', default=[],
151 160 help="Add a path to the list of libary directories (can be specified "
152 161 "multiple times)."
153 162 )
154 163 @magic_arguments.argument(
155 164 '-I', '--include', action='append', default=[],
156 165 help="Add a path to the list of include directories (can be specified "
157 166 "multiple times)."
158 167 )
159 168 @magic_arguments.argument(
160 169 '-+', '--cplus', action='store_true', default=False,
161 170 help="Output a C++ rather than C file."
162 171 )
163 172 @magic_arguments.argument(
164 173 '-f', '--force', action='store_true', default=False,
165 174 help="Force the compilation of a new module, even if the source has been "
166 175 "previously compiled."
167 176 )
168 177 @magic_arguments.argument(
169 178 '-a', '--annotate', action='store_true', default=False,
170 179 help="Produce a colorized HTML version of the source."
171 180 )
172 181 @cell_magic
173 182 def cython(self, line, cell):
174 183 """Compile and import everything from a Cython code cell.
175 184
176 185 The contents of the cell are written to a `.pyx` file in the
177 186 directory `IPYTHONDIR/cython` using a filename with the hash of the
178 187 code. This file is then cythonized and compiled. The resulting module
179 188 is imported and all of its symbols are injected into the user's
180 189 namespace. The usage is similar to that of `%%cython_pyximport` but
181 190 you don't have to pass a module name::
182 191
183 192 %%cython
184 193 def f(x):
185 194 return 2.0*x
186 195
187 196 To compile OpenMP codes, pass the required `--compile-args`
188 197 and `--link-args`. For example with gcc::
189 198
190 199 %%cython --compile-args=-fopenmp --link-args=-fopenmp
191 200 ...
192 201 """
193 202 args = magic_arguments.parse_argstring(self.cython, line)
194 203 code = cell if cell.endswith('\n') else cell+'\n'
195 204 lib_dir = os.path.join(get_ipython_cache_dir(), 'cython')
196 205 quiet = True
197 206 key = code, sys.version_info, sys.executable, Cython.__version__
198 207
199 208 if not os.path.exists(lib_dir):
200 209 os.makedirs(lib_dir)
201 210
202 211 if args.force:
203 212 # Force a new module name by adding the current time to the
204 213 # key which is hashed to determine the module name.
205 214 key += time.time(),
206 215
207 216 module_name = "_cython_magic_" + hashlib.md5(str(key).encode('utf-8')).hexdigest()
208 217 module_path = os.path.join(lib_dir, module_name + self.so_ext)
209 218
210 219 have_module = os.path.isfile(module_path)
211 220 need_cythonize = not have_module
212 221
213 222 if args.annotate:
214 223 html_file = os.path.join(lib_dir, module_name + '.html')
215 224 if not os.path.isfile(html_file):
216 225 need_cythonize = True
217 226
218 227 if need_cythonize:
219 228 c_include_dirs = args.include
220 229 if 'numpy' in code:
221 230 import numpy
222 231 c_include_dirs.append(numpy.get_include())
223 232 pyx_file = os.path.join(lib_dir, module_name + '.pyx')
224 233 pyx_file = py3compat.cast_bytes_py2(pyx_file, encoding=sys.getfilesystemencoding())
225 234 with io.open(pyx_file, 'w', encoding='utf-8') as f:
226 235 f.write(code)
227 236 extension = Extension(
228 237 name = module_name,
229 238 sources = [pyx_file],
230 239 include_dirs = c_include_dirs,
231 240 library_dirs = args.library_dirs,
232 241 extra_compile_args = args.compile_args,
233 242 extra_link_args = args.link_args,
234 243 libraries = args.lib,
235 244 language = 'c++' if args.cplus else 'c',
236 245 )
237 246 build_extension = self._get_build_extension()
238 247 try:
239 248 opts = dict(
240 249 quiet=quiet,
241 250 annotate = args.annotate,
242 251 force = True,
243 252 )
244 253 build_extension.extensions = cythonize([extension], **opts)
245 254 except CompileError:
246 255 return
247 256
248 257 if not have_module:
249 258 build_extension.build_temp = os.path.dirname(pyx_file)
250 259 build_extension.build_lib = lib_dir
251 260 build_extension.run()
252 261 self._code_cache[key] = module_name
253 262
254 263 module = imp.load_dynamic(module_name, module_path)
255 264 self._import_all(module)
256 265
257 266 if args.annotate:
258 267 try:
259 268 with io.open(html_file, encoding='utf-8') as f:
260 269 annotated_html = f.read()
261 270 except IOError as e:
262 271 # File could not be opened. Most likely the user has a version
263 272 # of Cython before 0.15.1 (when `cythonize` learned the
264 273 # `force` keyword argument) and has already compiled this
265 274 # exact source without annotation.
266 275 print('Cython completed successfully but the annotated '
267 276 'source could not be read.', file=sys.stderr)
268 277 print(e, file=sys.stderr)
269 278 else:
270 279 return display.HTML(self.clean_annotated_html(annotated_html))
271 280
272 281 @property
273 282 def so_ext(self):
274 283 """The extension suffix for compiled modules."""
275 284 try:
276 285 return self._so_ext
277 286 except AttributeError:
278 287 self._so_ext = self._get_build_extension().get_ext_filename('')
279 288 return self._so_ext
280 289
281 290 def _clear_distutils_mkpath_cache(self):
282 291 """clear distutils mkpath cache
283 292
284 293 prevents distutils from skipping re-creation of dirs that have been removed
285 294 """
286 295 try:
287 296 from distutils.dir_util import _path_created
288 297 except ImportError:
289 298 pass
290 299 else:
291 300 _path_created.clear()
292 301
293 302 def _get_build_extension(self):
294 303 self._clear_distutils_mkpath_cache()
295 304 dist = Distribution()
296 305 config_files = dist.find_config_files()
297 306 try:
298 307 config_files.remove('setup.cfg')
299 308 except ValueError:
300 309 pass
301 310 dist.parse_config_files(config_files)
302 311 build_extension = build_ext(dist)
303 312 build_extension.finalize_options()
304 313 return build_extension
305 314
306 315 @staticmethod
307 316 def clean_annotated_html(html):
308 317 """Clean up the annotated HTML source.
309 318
310 319 Strips the link to the generated C or C++ file, which we do not
311 320 present to the user.
312 321 """
313 322 r = re.compile('<p>Raw output: <a href="(.*)">(.*)</a>')
314 323 html = '\n'.join(l for l in html.splitlines() if not r.match(l))
315 324 return html
316 325
317 326 __doc__ = __doc__.format(
318 327 CYTHON_DOC = ' '*8 + CythonMagics.cython.__doc__,
319 328 CYTHON_INLINE_DOC = ' '*8 + CythonMagics.cython_inline.__doc__,
320 329 CYTHON_PYXIMPORT_DOC = ' '*8 + CythonMagics.cython_pyximport.__doc__,
321 330 )
322 331
323 332 def load_ipython_extension(ip):
324 333 """Load the extension in IPython."""
325 334 ip.register_magics(CythonMagics)
@@ -1,367 +1,371 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 ===========
4 4 octavemagic
5 5 ===========
6 6
7 7 Magics for interacting with Octave via oct2py.
8 8
9 9 .. note::
10 10
11 11 The ``oct2py`` module needs to be installed separately and
12 12 can be obtained using ``easy_install`` or ``pip``.
13 13
14 You will also need a working copy of GNU Octave.
15
14 16 Usage
15 17 =====
16 18
19 To enable the magics below, execute ``%load_ext octavemagic``.
20
17 21 ``%octave``
18 22
19 23 {OCTAVE_DOC}
20 24
21 25 ``%octave_push``
22 26
23 27 {OCTAVE_PUSH_DOC}
24 28
25 29 ``%octave_pull``
26 30
27 31 {OCTAVE_PULL_DOC}
28 32
29 33 """
30 34
31 35 #-----------------------------------------------------------------------------
32 36 # Copyright (C) 2012 The IPython Development Team
33 37 #
34 38 # Distributed under the terms of the BSD License. The full license is in
35 39 # the file COPYING, distributed as part of this software.
36 40 #-----------------------------------------------------------------------------
37 41
38 42 import tempfile
39 43 from glob import glob
40 44 from shutil import rmtree
41 45
42 46 import numpy as np
43 47 import oct2py
44 48 from xml.dom import minidom
45 49
46 50 from IPython.core.displaypub import publish_display_data
47 51 from IPython.core.magic import (Magics, magics_class, line_magic,
48 52 line_cell_magic, needs_local_scope)
49 53 from IPython.testing.skipdoctest import skip_doctest
50 54 from IPython.core.magic_arguments import (
51 55 argument, magic_arguments, parse_argstring
52 56 )
53 57 from IPython.utils.py3compat import unicode_to_str
54 58
55 59 class OctaveMagicError(oct2py.Oct2PyError):
56 60 pass
57 61
58 62 _mimetypes = {'png' : 'image/png',
59 63 'svg' : 'image/svg+xml',
60 64 'jpg' : 'image/jpeg',
61 65 'jpeg': 'image/jpeg'}
62 66
63 67 @magics_class
64 68 class OctaveMagics(Magics):
65 69 """A set of magics useful for interactive work with Octave via oct2py.
66 70 """
67 71 def __init__(self, shell):
68 72 """
69 73 Parameters
70 74 ----------
71 75 shell : IPython shell
72 76
73 77 """
74 78 super(OctaveMagics, self).__init__(shell)
75 79 self._oct = oct2py.Oct2Py()
76 80 self._plot_format = 'png'
77 81
78 82 # Allow publish_display_data to be overridden for
79 83 # testing purposes.
80 84 self._publish_display_data = publish_display_data
81 85
82 86
83 87 def _fix_gnuplot_svg_size(self, image, size=None):
84 88 """
85 89 GnuPlot SVGs do not have height/width attributes. Set
86 90 these to be the same as the viewBox, so that the browser
87 91 scales the image correctly.
88 92
89 93 Parameters
90 94 ----------
91 95 image : str
92 96 SVG data.
93 97 size : tuple of int
94 98 Image width, height.
95 99
96 100 """
97 101 (svg,) = minidom.parseString(image).getElementsByTagName('svg')
98 102 viewbox = svg.getAttribute('viewBox').split(' ')
99 103
100 104 if size is not None:
101 105 width, height = size
102 106 else:
103 107 width, height = viewbox[2:]
104 108
105 109 svg.setAttribute('width', '%dpx' % width)
106 110 svg.setAttribute('height', '%dpx' % height)
107 111 return svg.toxml()
108 112
109 113
110 114 @skip_doctest
111 115 @line_magic
112 116 def octave_push(self, line):
113 117 '''
114 118 Line-level magic that pushes a variable to Octave.
115 119
116 120 `line` should be made up of whitespace separated variable names in the
117 121 IPython namespace::
118 122
119 123 In [7]: import numpy as np
120 124
121 125 In [8]: X = np.arange(5)
122 126
123 127 In [9]: X.mean()
124 128 Out[9]: 2.0
125 129
126 130 In [10]: %octave_push X
127 131
128 132 In [11]: %octave mean(X)
129 133 Out[11]: 2.0
130 134
131 135 '''
132 136 inputs = line.split(' ')
133 137 for input in inputs:
134 138 input = unicode_to_str(input)
135 139 self._oct.put(input, self.shell.user_ns[input])
136 140
137 141
138 142 @skip_doctest
139 143 @line_magic
140 144 def octave_pull(self, line):
141 145 '''
142 146 Line-level magic that pulls a variable from Octave.
143 147
144 148 In [18]: _ = %octave x = [1 2; 3 4]; y = 'hello'
145 149
146 150 In [19]: %octave_pull x y
147 151
148 152 In [20]: x
149 153 Out[20]:
150 154 array([[ 1., 2.],
151 155 [ 3., 4.]])
152 156
153 157 In [21]: y
154 158 Out[21]: 'hello'
155 159
156 160 '''
157 161 outputs = line.split(' ')
158 162 for output in outputs:
159 163 output = unicode_to_str(output)
160 164 self.shell.push({output: self._oct.get(output)})
161 165
162 166
163 167 @skip_doctest
164 168 @magic_arguments()
165 169 @argument(
166 170 '-i', '--input', action='append',
167 171 help='Names of input variables to be pushed to Octave. Multiple names '
168 172 'can be passed, separated by commas with no whitespace.'
169 173 )
170 174 @argument(
171 175 '-o', '--output', action='append',
172 176 help='Names of variables to be pulled from Octave after executing cell '
173 177 'body. Multiple names can be passed, separated by commas with no '
174 178 'whitespace.'
175 179 )
176 180 @argument(
177 181 '-s', '--size', action='store',
178 182 help='Pixel size of plots, "width,height". Default is "-s 400,250".'
179 183 )
180 184 @argument(
181 185 '-f', '--format', action='store',
182 186 help='Plot format (png, svg or jpg).'
183 187 )
184 188
185 189 @needs_local_scope
186 190 @argument(
187 191 'code',
188 192 nargs='*',
189 193 )
190 194 @line_cell_magic
191 195 def octave(self, line, cell=None, local_ns=None):
192 196 '''
193 197 Execute code in Octave, and pull some of the results back into the
194 198 Python namespace.
195 199
196 200 In [9]: %octave X = [1 2; 3 4]; mean(X)
197 201 Out[9]: array([[ 2., 3.]])
198 202
199 203 As a cell, this will run a block of Octave code, without returning any
200 204 value::
201 205
202 206 In [10]: %%octave
203 207 ....: p = [-2, -1, 0, 1, 2]
204 208 ....: polyout(p, 'x')
205 209
206 210 -2*x^4 - 1*x^3 + 0*x^2 + 1*x^1 + 2
207 211
208 212 In the notebook, plots are published as the output of the cell, e.g.
209 213
210 214 %octave plot([1 2 3], [4 5 6])
211 215
212 216 will create a line plot.
213 217
214 218 Objects can be passed back and forth between Octave and IPython via the
215 219 -i and -o flags in line::
216 220
217 221 In [14]: Z = np.array([1, 4, 5, 10])
218 222
219 223 In [15]: %octave -i Z mean(Z)
220 224 Out[15]: array([ 5.])
221 225
222 226
223 227 In [16]: %octave -o W W = Z * mean(Z)
224 228 Out[16]: array([ 5., 20., 25., 50.])
225 229
226 230 In [17]: W
227 231 Out[17]: array([ 5., 20., 25., 50.])
228 232
229 233 The size and format of output plots can be specified::
230 234
231 235 In [18]: %%octave -s 600,800 -f svg
232 236 ...: plot([1, 2, 3]);
233 237
234 238 '''
235 239 args = parse_argstring(self.octave, line)
236 240
237 241 # arguments 'code' in line are prepended to the cell lines
238 242 if cell is None:
239 243 code = ''
240 244 return_output = True
241 245 else:
242 246 code = cell
243 247 return_output = False
244 248
245 249 code = ' '.join(args.code) + code
246 250
247 251 # if there is no local namespace then default to an empty dict
248 252 if local_ns is None:
249 253 local_ns = {}
250 254
251 255 if args.input:
252 256 for input in ','.join(args.input).split(','):
253 257 input = unicode_to_str(input)
254 258 try:
255 259 val = local_ns[input]
256 260 except KeyError:
257 261 val = self.shell.user_ns[input]
258 262 self._oct.put(input, val)
259 263
260 264 # generate plots in a temporary directory
261 265 plot_dir = tempfile.mkdtemp().replace('\\', '/')
262 266 if args.size is not None:
263 267 size = args.size
264 268 else:
265 269 size = '400,240'
266 270
267 271 if args.format is not None:
268 272 plot_format = args.format
269 273 else:
270 274 plot_format = 'png'
271 275
272 276 pre_call = '''
273 277 global __ipy_figures = [];
274 278 page_screen_output(0);
275 279
276 280 function fig_create(src, event)
277 281 global __ipy_figures;
278 282 __ipy_figures(size(__ipy_figures) + 1) = src;
279 283 set(src, "visible", "off");
280 284 end
281 285
282 286 set(0, 'DefaultFigureCreateFcn', @fig_create);
283 287
284 288 close all;
285 289 clear ans;
286 290
287 291 # ___<end_pre_call>___ #
288 292 '''
289 293
290 294 post_call = '''
291 295 # ___<start_post_call>___ #
292 296
293 297 # Save output of the last execution
294 298 if exist("ans") == 1
295 299 _ = ans;
296 300 else
297 301 _ = nan;
298 302 end
299 303
300 304 for f = __ipy_figures
301 305 outfile = sprintf('%(plot_dir)s/__ipy_oct_fig_%%03d.png', f);
302 306 try
303 307 print(f, outfile, '-d%(plot_format)s', '-tight', '-S%(size)s');
304 308 end
305 309 end
306 310
307 311 ''' % locals()
308 312
309 313 code = ' '.join((pre_call, code, post_call))
310 314 try:
311 315 text_output = self._oct.run(code, verbose=False)
312 316 except (oct2py.Oct2PyError) as exception:
313 317 msg = exception.message
314 318 msg = msg.split('# ___<end_pre_call>___ #')[1]
315 319 msg = msg.split('# ___<start_post_call>___ #')[0]
316 320 raise OctaveMagicError('Octave could not complete execution. '
317 321 'Traceback (currently broken in oct2py): %s'
318 322 % msg)
319 323
320 324 key = 'OctaveMagic.Octave'
321 325 display_data = []
322 326
323 327 # Publish text output
324 328 if text_output:
325 329 display_data.append((key, {'text/plain': text_output}))
326 330
327 331 # Publish images
328 332 images = [open(imgfile, 'rb').read() for imgfile in \
329 333 glob("%s/*" % plot_dir)]
330 334 rmtree(plot_dir)
331 335
332 336 plot_mime_type = _mimetypes.get(plot_format, 'image/png')
333 337 width, height = [int(s) for s in size.split(',')]
334 338 for image in images:
335 339 if plot_format == 'svg':
336 340 image = self._fix_gnuplot_svg_size(image, size=(width, height))
337 341 display_data.append((key, {plot_mime_type: image}))
338 342
339 343 if args.output:
340 344 for output in ','.join(args.output).split(','):
341 345 output = unicode_to_str(output)
342 346 self.shell.push({output: self._oct.get(output)})
343 347
344 348 for source, data in display_data:
345 349 self._publish_display_data(source, data)
346 350
347 351 if return_output:
348 352 ans = self._oct.get('_')
349 353
350 354 # Unfortunately, Octave doesn't have a "None" object,
351 355 # so we can't return any NaN outputs
352 356 if np.isscalar(ans) and np.isnan(ans):
353 357 ans = None
354 358
355 359 return ans
356 360
357 361
358 362 __doc__ = __doc__.format(
359 363 OCTAVE_DOC = ' '*8 + OctaveMagics.octave.__doc__,
360 364 OCTAVE_PUSH_DOC = ' '*8 + OctaveMagics.octave_push.__doc__,
361 365 OCTAVE_PULL_DOC = ' '*8 + OctaveMagics.octave_pull.__doc__
362 366 )
363 367
364 368
365 369 def load_ipython_extension(ip):
366 370 """Load the extension in IPython."""
367 371 ip.register_magics(OctaveMagics)
@@ -1,684 +1,693 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 ======
4 4 Rmagic
5 5 ======
6 6
7 7 Magic command interface for interactive work with R via rpy2
8 8
9 .. note::
10
11 The ``rpy2`` package needs to be installed separately. It
12 can be obtained using ``easy_install`` or ``pip``.
13
14 You will also need a working copy of R.
15
9 16 Usage
10 17 =====
11 18
19 To enable the magics below, execute ``%load_ext rmagic``.
20
12 21 ``%R``
13 22
14 23 {R_DOC}
15 24
16 25 ``%Rpush``
17 26
18 27 {RPUSH_DOC}
19 28
20 29 ``%Rpull``
21 30
22 31 {RPULL_DOC}
23 32
24 33 ``%Rget``
25 34
26 35 {RGET_DOC}
27 36
28 37 """
29 38
30 39 #-----------------------------------------------------------------------------
31 40 # Copyright (C) 2012 The IPython Development Team
32 41 #
33 42 # Distributed under the terms of the BSD License. The full license is in
34 43 # the file COPYING, distributed as part of this software.
35 44 #-----------------------------------------------------------------------------
36 45
37 46 import sys
38 47 import tempfile
39 48 from glob import glob
40 49 from shutil import rmtree
41 50
42 51 # numpy and rpy2 imports
43 52
44 53 import numpy as np
45 54
46 55 import rpy2.rinterface as ri
47 56 import rpy2.robjects as ro
48 57 try:
49 58 from rpy2.robjects import pandas2ri
50 59 pandas2ri.activate()
51 60 except ImportError:
52 61 pandas2ri = None
53 62 from rpy2.robjects import numpy2ri
54 63 numpy2ri.activate()
55 64
56 65 # IPython imports
57 66
58 67 from IPython.core.displaypub import publish_display_data
59 68 from IPython.core.magic import (Magics, magics_class, line_magic,
60 69 line_cell_magic, needs_local_scope)
61 70 from IPython.testing.skipdoctest import skip_doctest
62 71 from IPython.core.magic_arguments import (
63 72 argument, magic_arguments, parse_argstring
64 73 )
65 74 from IPython.external.simplegeneric import generic
66 75 from IPython.utils.py3compat import str_to_unicode, unicode_to_str, PY3
67 76
68 77 class RInterpreterError(ri.RRuntimeError):
69 78 """An error when running R code in a %%R magic cell."""
70 79 def __init__(self, line, err, stdout):
71 80 self.line = line
72 81 self.err = err.rstrip()
73 82 self.stdout = stdout.rstrip()
74 83
75 84 def __unicode__(self):
76 85 s = 'Failed to parse and evaluate line %r.\nR error message: %r' % \
77 86 (self.line, self.err)
78 87 if self.stdout and (self.stdout != self.err):
79 88 s += '\nR stdout:\n' + self.stdout
80 89 return s
81 90
82 91 if PY3:
83 92 __str__ = __unicode__
84 93 else:
85 94 def __str__(self):
86 95 return unicode_to_str(unicode(self), 'utf-8')
87 96
88 97 def Rconverter(Robj, dataframe=False):
89 98 """
90 99 Convert an object in R's namespace to one suitable
91 100 for ipython's namespace.
92 101
93 102 For a data.frame, it tries to return a structured array.
94 103 It first checks for colnames, then names.
95 104 If all are NULL, it returns np.asarray(Robj), else
96 105 it tries to construct a recarray
97 106
98 107 Parameters
99 108 ----------
100 109
101 110 Robj: an R object returned from rpy2
102 111 """
103 112 is_data_frame = ro.r('is.data.frame')
104 113 colnames = ro.r('colnames')
105 114 rownames = ro.r('rownames') # with pandas, these could be used for the index
106 115 names = ro.r('names')
107 116
108 117 if dataframe:
109 118 as_data_frame = ro.r('as.data.frame')
110 119 cols = colnames(Robj)
111 120 _names = names(Robj)
112 121 if cols != ri.NULL:
113 122 Robj = as_data_frame(Robj)
114 123 names = tuple(np.array(cols))
115 124 elif _names != ri.NULL:
116 125 names = tuple(np.array(_names))
117 126 else: # failed to find names
118 127 return np.asarray(Robj)
119 128 Robj = np.rec.fromarrays(Robj, names = names)
120 129 return np.asarray(Robj)
121 130
122 131 @generic
123 132 def pyconverter(pyobj):
124 133 """Convert Python objects to R objects. Add types using the decorator:
125 134
126 135 @pyconverter.when_type
127 136 """
128 137 return pyobj
129 138
130 139 # The default conversion for lists seems to make them a nested list. That has
131 140 # some advantages, but is rarely convenient, so for interactive use, we convert
132 141 # lists to a numpy array, which becomes an R vector.
133 142 @pyconverter.when_type(list)
134 143 def pyconverter_list(pyobj):
135 144 return np.asarray(pyobj)
136 145
137 146 if pandas2ri is None:
138 147 # pandas2ri was new in rpy2 2.3.3, so for now we'll fallback to pandas'
139 148 # conversion function.
140 149 try:
141 150 from pandas import DataFrame
142 151 from pandas.rpy.common import convert_to_r_dataframe
143 152 @pyconverter.when_type(DataFrame)
144 153 def pyconverter_dataframe(pyobj):
145 154 return convert_to_r_dataframe(pyobj, strings_as_factors=True)
146 155 except ImportError:
147 156 pass
148 157
149 158 @magics_class
150 159 class RMagics(Magics):
151 160 """A set of magics useful for interactive work with R via rpy2.
152 161 """
153 162
154 163 def __init__(self, shell, Rconverter=Rconverter,
155 164 pyconverter=pyconverter,
156 165 cache_display_data=False):
157 166 """
158 167 Parameters
159 168 ----------
160 169
161 170 shell : IPython shell
162 171
163 172 Rconverter : callable
164 173 To be called on values taken from R before putting them in the
165 174 IPython namespace.
166 175
167 176 pyconverter : callable
168 177 To be called on values in ipython namespace before
169 178 assigning to variables in rpy2.
170 179
171 180 cache_display_data : bool
172 181 If True, the published results of the final call to R are
173 182 cached in the variable 'display_cache'.
174 183
175 184 """
176 185 super(RMagics, self).__init__(shell)
177 186 self.cache_display_data = cache_display_data
178 187
179 188 self.r = ro.R()
180 189
181 190 self.Rstdout_cache = []
182 191 self.pyconverter = pyconverter
183 192 self.Rconverter = Rconverter
184 193
185 194 def eval(self, line):
186 195 '''
187 196 Parse and evaluate a line of R code with rpy2.
188 197 Returns the output to R's stdout() connection,
189 198 the value generated by evaluating the code, and a
190 199 boolean indicating whether the return value would be
191 200 visible if the line of code were evaluated in an R REPL.
192 201
193 202 R Code evaluation and visibility determination are
194 203 done via an R call of the form withVisible({<code>})
195 204
196 205 '''
197 206 old_writeconsole = ri.get_writeconsole()
198 207 ri.set_writeconsole(self.write_console)
199 208 try:
200 209 res = ro.r("withVisible({%s})" % line)
201 210 value = res[0] #value (R object)
202 211 visible = ro.conversion.ri2py(res[1])[0] #visible (boolean)
203 212 except (ri.RRuntimeError, ValueError) as exception:
204 213 warning_or_other_msg = self.flush() # otherwise next return seems to have copy of error
205 214 raise RInterpreterError(line, str_to_unicode(str(exception)), warning_or_other_msg)
206 215 text_output = self.flush()
207 216 ri.set_writeconsole(old_writeconsole)
208 217 return text_output, value, visible
209 218
210 219 def write_console(self, output):
211 220 '''
212 221 A hook to capture R's stdout in a cache.
213 222 '''
214 223 self.Rstdout_cache.append(output)
215 224
216 225 def flush(self):
217 226 '''
218 227 Flush R's stdout cache to a string, returning the string.
219 228 '''
220 229 value = ''.join([str_to_unicode(s, 'utf-8') for s in self.Rstdout_cache])
221 230 self.Rstdout_cache = []
222 231 return value
223 232
224 233 @skip_doctest
225 234 @needs_local_scope
226 235 @line_magic
227 236 def Rpush(self, line, local_ns=None):
228 237 '''
229 238 A line-level magic for R that pushes
230 239 variables from python to rpy2. The line should be made up
231 240 of whitespace separated variable names in the IPython
232 241 namespace::
233 242
234 243 In [7]: import numpy as np
235 244
236 245 In [8]: X = np.array([4.5,6.3,7.9])
237 246
238 247 In [9]: X.mean()
239 248 Out[9]: 6.2333333333333343
240 249
241 250 In [10]: %Rpush X
242 251
243 252 In [11]: %R mean(X)
244 253 Out[11]: array([ 6.23333333])
245 254
246 255 '''
247 256 if local_ns is None:
248 257 local_ns = {}
249 258
250 259 inputs = line.split(' ')
251 260 for input in inputs:
252 261 try:
253 262 val = local_ns[input]
254 263 except KeyError:
255 264 try:
256 265 val = self.shell.user_ns[input]
257 266 except KeyError:
258 267 # reraise the KeyError as a NameError so that it looks like
259 268 # the standard python behavior when you use an unnamed
260 269 # variable
261 270 raise NameError("name '%s' is not defined" % input)
262 271
263 272 self.r.assign(input, self.pyconverter(val))
264 273
265 274 @skip_doctest
266 275 @magic_arguments()
267 276 @argument(
268 277 '-d', '--as_dataframe', action='store_true',
269 278 default=False,
270 279 help='Convert objects to data.frames before returning to ipython.'
271 280 )
272 281 @argument(
273 282 'outputs',
274 283 nargs='*',
275 284 )
276 285 @line_magic
277 286 def Rpull(self, line):
278 287 '''
279 288 A line-level magic for R that pulls
280 289 variables from python to rpy2::
281 290
282 291 In [18]: _ = %R x = c(3,4,6.7); y = c(4,6,7); z = c('a',3,4)
283 292
284 293 In [19]: %Rpull x y z
285 294
286 295 In [20]: x
287 296 Out[20]: array([ 3. , 4. , 6.7])
288 297
289 298 In [21]: y
290 299 Out[21]: array([ 4., 6., 7.])
291 300
292 301 In [22]: z
293 302 Out[22]:
294 303 array(['a', '3', '4'],
295 304 dtype='|S1')
296 305
297 306
298 307 If --as_dataframe, then each object is returned as a structured array
299 308 after first passed through "as.data.frame" in R before
300 309 being calling self.Rconverter.
301 310 This is useful when a structured array is desired as output, or
302 311 when the object in R has mixed data types.
303 312 See the %%R docstring for more examples.
304 313
305 314 Notes
306 315 -----
307 316
308 317 Beware that R names can have '.' so this is not fool proof.
309 318 To avoid this, don't name your R objects with '.'s...
310 319
311 320 '''
312 321 args = parse_argstring(self.Rpull, line)
313 322 outputs = args.outputs
314 323 for output in outputs:
315 324 self.shell.push({output:self.Rconverter(self.r(output),dataframe=args.as_dataframe)})
316 325
317 326 @skip_doctest
318 327 @magic_arguments()
319 328 @argument(
320 329 '-d', '--as_dataframe', action='store_true',
321 330 default=False,
322 331 help='Convert objects to data.frames before returning to ipython.'
323 332 )
324 333 @argument(
325 334 'output',
326 335 nargs=1,
327 336 type=str,
328 337 )
329 338 @line_magic
330 339 def Rget(self, line):
331 340 '''
332 341 Return an object from rpy2, possibly as a structured array (if possible).
333 342 Similar to Rpull except only one argument is accepted and the value is
334 343 returned rather than pushed to self.shell.user_ns::
335 344
336 345 In [3]: dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')]
337 346
338 347 In [4]: datapy = np.array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c'), (4, 5, 'e')], dtype=dtype)
339 348
340 349 In [5]: %R -i datapy
341 350
342 351 In [6]: %Rget datapy
343 352 Out[6]:
344 353 array([['1', '2', '3', '4'],
345 354 ['2', '3', '2', '5'],
346 355 ['a', 'b', 'c', 'e']],
347 356 dtype='|S1')
348 357
349 358 In [7]: %Rget -d datapy
350 359 Out[7]:
351 360 array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c'), (4, 5.0, 'e')],
352 361 dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')])
353 362
354 363 '''
355 364 args = parse_argstring(self.Rget, line)
356 365 output = args.output
357 366 return self.Rconverter(self.r(output[0]),dataframe=args.as_dataframe)
358 367
359 368
360 369 @skip_doctest
361 370 @magic_arguments()
362 371 @argument(
363 372 '-i', '--input', action='append',
364 373 help='Names of input variable from shell.user_ns to be assigned to R variables of the same names after calling self.pyconverter. Multiple names can be passed separated only by commas with no whitespace.'
365 374 )
366 375 @argument(
367 376 '-o', '--output', action='append',
368 377 help='Names of variables to be pushed from rpy2 to shell.user_ns after executing cell body and applying self.Rconverter. Multiple names can be passed separated only by commas with no whitespace.'
369 378 )
370 379 @argument(
371 380 '-w', '--width', type=int,
372 381 help='Width of png plotting device sent as an argument to *png* in R.'
373 382 )
374 383 @argument(
375 384 '-h', '--height', type=int,
376 385 help='Height of png plotting device sent as an argument to *png* in R.'
377 386 )
378 387
379 388 @argument(
380 389 '-d', '--dataframe', action='append',
381 390 help='Convert these objects to data.frames and return as structured arrays.'
382 391 )
383 392 @argument(
384 393 '-u', '--units', type=unicode, choices=["px", "in", "cm", "mm"],
385 394 help='Units of png plotting device sent as an argument to *png* in R. One of ["px", "in", "cm", "mm"].'
386 395 )
387 396 @argument(
388 397 '-r', '--res', type=int,
389 398 help='Resolution of png plotting device sent as an argument to *png* in R. Defaults to 72 if *units* is one of ["in", "cm", "mm"].'
390 399 )
391 400 @argument(
392 401 '-p', '--pointsize', type=int,
393 402 help='Pointsize of png plotting device sent as an argument to *png* in R.'
394 403 )
395 404 @argument(
396 405 '-b', '--bg',
397 406 help='Background of png plotting device sent as an argument to *png* in R.'
398 407 )
399 408 @argument(
400 409 '-n', '--noreturn',
401 410 help='Force the magic to not return anything.',
402 411 action='store_true',
403 412 default=False
404 413 )
405 414 @argument(
406 415 'code',
407 416 nargs='*',
408 417 )
409 418 @needs_local_scope
410 419 @line_cell_magic
411 420 def R(self, line, cell=None, local_ns=None):
412 421 '''
413 422 Execute code in R, and pull some of the results back into the Python namespace.
414 423
415 424 In line mode, this will evaluate an expression and convert the returned value to a Python object.
416 425 The return value is determined by rpy2's behaviour of returning the result of evaluating the
417 426 final line.
418 427
419 428 Multiple R lines can be executed by joining them with semicolons::
420 429
421 430 In [9]: %R X=c(1,4,5,7); sd(X); mean(X)
422 431 Out[9]: array([ 4.25])
423 432
424 433 In cell mode, this will run a block of R code. The resulting value
425 434 is printed if it would printed be when evaluating the same code
426 435 within a standard R REPL.
427 436
428 Nothing is returned to python by default in cell mode.
437 Nothing is returned to python by default in cell mode::
429 438
430 439 In [10]: %%R
431 440 ....: Y = c(2,4,3,9)
432 441 ....: summary(lm(Y~X))
433
442
434 443 Call:
435 444 lm(formula = Y ~ X)
436 445
437 446 Residuals:
438 447 1 2 3 4
439 448 0.88 -0.24 -2.28 1.64
440 449
441 450 Coefficients:
442 451 Estimate Std. Error t value Pr(>|t|)
443 452 (Intercept) 0.0800 2.3000 0.035 0.975
444 453 X 1.0400 0.4822 2.157 0.164
445 454
446 455 Residual standard error: 2.088 on 2 degrees of freedom
447 456 Multiple R-squared: 0.6993,Adjusted R-squared: 0.549
448 457 F-statistic: 4.651 on 1 and 2 DF, p-value: 0.1638
449 458
450 In the notebook, plots are published as the output of the cell.
459 In the notebook, plots are published as the output of the cell::
451 460
452 %R plot(X, Y)
461 %R plot(X, Y)
453 462
454 463 will create a scatter plot of X bs Y.
455 464
456 465 If cell is not None and line has some R code, it is prepended to
457 466 the R code in cell.
458 467
459 468 Objects can be passed back and forth between rpy2 and python via the -i -o flags in line::
460 469
461 470 In [14]: Z = np.array([1,4,5,10])
462 471
463 472 In [15]: %R -i Z mean(Z)
464 473 Out[15]: array([ 5.])
465 474
466 475
467 476 In [16]: %R -o W W=Z*mean(Z)
468 477 Out[16]: array([ 5., 20., 25., 50.])
469 478
470 479 In [17]: W
471 480 Out[17]: array([ 5., 20., 25., 50.])
472 481
473 482 The return value is determined by these rules:
474 483
475 484 * If the cell is not None, the magic returns None.
476 485
477 486 * If the cell evaluates as False, the resulting value is returned
478 unless the final line prints something to the console, in
479 which case None is returned.
487 unless the final line prints something to the console, in
488 which case None is returned.
480 489
481 490 * If the final line results in a NULL value when evaluated
482 by rpy2, then None is returned.
491 by rpy2, then None is returned.
483 492
484 493 * No attempt is made to convert the final value to a structured array.
485 Use the --dataframe flag or %Rget to push / return a structured array.
494 Use the --dataframe flag or %Rget to push / return a structured array.
486 495
487 496 * If the -n flag is present, there is no return value.
488 497
489 498 * A trailing ';' will also result in no return value as the last
490 value in the line is an empty string.
499 value in the line is an empty string.
491 500
492 501 The --dataframe argument will attempt to return structured arrays.
493 502 This is useful for dataframes with
494 503 mixed data types. Note also that for a data.frame,
495 504 if it is returned as an ndarray, it is transposed::
496 505
497 506 In [18]: dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')]
498 507
499 508 In [19]: datapy = np.array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c'), (4, 5, 'e')], dtype=dtype)
500 509
501 510 In [20]: %%R -o datar
502 511 datar = datapy
503 512 ....:
504 513
505 514 In [21]: datar
506 515 Out[21]:
507 516 array([['1', '2', '3', '4'],
508 517 ['2', '3', '2', '5'],
509 518 ['a', 'b', 'c', 'e']],
510 519 dtype='|S1')
511 520
512 521 In [22]: %%R -d datar
513 522 datar = datapy
514 523 ....:
515 524
516 525 In [23]: datar
517 526 Out[23]:
518 527 array([(1, 2.9, 'a'), (2, 3.5, 'b'), (3, 2.1, 'c'), (4, 5.0, 'e')],
519 528 dtype=[('x', '<i4'), ('y', '<f8'), ('z', '|S1')])
520 529
521 530 The --dataframe argument first tries colnames, then names.
522 531 If both are NULL, it returns an ndarray (i.e. unstructured)::
523 532
524 533 In [1]: %R mydata=c(4,6,8.3); NULL
525 534
526 535 In [2]: %R -d mydata
527 536
528 537 In [3]: mydata
529 538 Out[3]: array([ 4. , 6. , 8.3])
530 539
531 540 In [4]: %R names(mydata) = c('a','b','c'); NULL
532 541
533 542 In [5]: %R -d mydata
534 543
535 544 In [6]: mydata
536 545 Out[6]:
537 546 array((4.0, 6.0, 8.3),
538 547 dtype=[('a', '<f8'), ('b', '<f8'), ('c', '<f8')])
539 548
540 549 In [7]: %R -o mydata
541 550
542 551 In [8]: mydata
543 552 Out[8]: array([ 4. , 6. , 8.3])
544 553
545 554 '''
546 555
547 556 args = parse_argstring(self.R, line)
548 557
549 558 # arguments 'code' in line are prepended to
550 559 # the cell lines
551 560
552 561 if cell is None:
553 562 code = ''
554 563 return_output = True
555 564 line_mode = True
556 565 else:
557 566 code = cell
558 567 return_output = False
559 568 line_mode = False
560 569
561 570 code = ' '.join(args.code) + code
562 571
563 572 # if there is no local namespace then default to an empty dict
564 573 if local_ns is None:
565 574 local_ns = {}
566 575
567 576 if args.input:
568 577 for input in ','.join(args.input).split(','):
569 578 try:
570 579 val = local_ns[input]
571 580 except KeyError:
572 581 try:
573 582 val = self.shell.user_ns[input]
574 583 except KeyError:
575 584 raise NameError("name '%s' is not defined" % input)
576 585 self.r.assign(input, self.pyconverter(val))
577 586
578 587 if getattr(args, 'units') is not None:
579 588 if args.units != "px" and getattr(args, 'res') is None:
580 589 args.res = 72
581 590 args.units = '"%s"' % args.units
582 591
583 592 png_argdict = dict([(n, getattr(args, n)) for n in ['units', 'res', 'height', 'width', 'bg', 'pointsize']])
584 593 png_args = ','.join(['%s=%s' % (o,v) for o, v in png_argdict.items() if v is not None])
585 594 # execute the R code in a temporary directory
586 595
587 596 tmpd = tempfile.mkdtemp()
588 597 self.r('png("%s/Rplots%%03d.png",%s)' % (tmpd.replace('\\', '/'), png_args))
589 598
590 599 text_output = ''
591 600 try:
592 601 if line_mode:
593 602 for line in code.split(';'):
594 603 text_result, result, visible = self.eval(line)
595 604 text_output += text_result
596 605 if text_result:
597 606 # the last line printed something to the console so we won't return it
598 607 return_output = False
599 608 else:
600 609 text_result, result, visible = self.eval(code)
601 610 text_output += text_result
602 611 if visible:
603 612 old_writeconsole = ri.get_writeconsole()
604 613 ri.set_writeconsole(self.write_console)
605 614 ro.r.show(result)
606 615 text_output += self.flush()
607 616 ri.set_writeconsole(old_writeconsole)
608 617
609 618 except RInterpreterError as e:
610 619 print(e.stdout)
611 620 if not e.stdout.endswith(e.err):
612 621 print(e.err)
613 622 rmtree(tmpd)
614 623 return
615 624
616 625 self.r('dev.off()')
617 626
618 627 # read out all the saved .png files
619 628
620 629 images = [open(imgfile, 'rb').read() for imgfile in glob("%s/Rplots*png" % tmpd)]
621 630
622 631 # now publish the images
623 632 # mimicking IPython/zmq/pylab/backend_inline.py
624 633 fmt = 'png'
625 634 mimetypes = { 'png' : 'image/png', 'svg' : 'image/svg+xml' }
626 635 mime = mimetypes[fmt]
627 636
628 637 # publish the printed R objects, if any
629 638
630 639 display_data = []
631 640 if text_output:
632 641 display_data.append(('RMagic.R', {'text/plain':text_output}))
633 642
634 643 # flush text streams before sending figures, helps a little with output
635 644 for image in images:
636 645 # synchronization in the console (though it's a bandaid, not a real sln)
637 646 sys.stdout.flush(); sys.stderr.flush()
638 647 display_data.append(('RMagic.R', {mime: image}))
639 648
640 649 # kill the temporary directory
641 650 rmtree(tmpd)
642 651
643 652 # try to turn every output into a numpy array
644 653 # this means that output are assumed to be castable
645 654 # as numpy arrays
646 655
647 656 if args.output:
648 657 for output in ','.join(args.output).split(','):
649 658 self.shell.push({output:self.Rconverter(self.r(output), dataframe=False)})
650 659
651 660 if args.dataframe:
652 661 for output in ','.join(args.dataframe).split(','):
653 662 self.shell.push({output:self.Rconverter(self.r(output), dataframe=True)})
654 663
655 664 for tag, disp_d in display_data:
656 665 publish_display_data(tag, disp_d)
657 666
658 667 # this will keep a reference to the display_data
659 668 # which might be useful to other objects who happen to use
660 669 # this method
661 670
662 671 if self.cache_display_data:
663 672 self.display_cache = display_data
664 673
665 674 # if in line mode and return_output, return the result as an ndarray
666 675 if return_output and not args.noreturn:
667 676 if result != ri.NULL:
668 677 return self.Rconverter(result, dataframe=False)
669 678
670 679 __doc__ = __doc__.format(
671 680 R_DOC = ' '*8 + RMagics.R.__doc__,
672 681 RPUSH_DOC = ' '*8 + RMagics.Rpush.__doc__,
673 682 RPULL_DOC = ' '*8 + RMagics.Rpull.__doc__,
674 683 RGET_DOC = ' '*8 + RMagics.Rget.__doc__
675 684 )
676 685
677 686
678 687 def load_ipython_extension(ip):
679 688 """Load the extension in IPython."""
680 689 ip.register_magics(RMagics)
681 690 # Initialising rpy2 interferes with readline. Since, at this point, we've
682 691 # probably just loaded rpy2, we reset the delimiters. See issue gh-2759.
683 692 if ip.has_readline:
684 693 ip.readline.set_completer_delims(ip.readline_delims)
General Comments 0
You need to be logged in to leave comments. Login now