##// END OF EJS Templates
Use -I (capital) to match gcc stle and show -l usage without spaces.
Fernando Perez -
Show More
@@ -1,200 +1,200 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 Cython related magics.
4 4
5 5 Author:
6 6 * Brian Granger
7 7
8 8 Parts of this code were taken from Cython.inline.
9 9 """
10 10 #-----------------------------------------------------------------------------
11 11 # Copyright (C) 2010-2011, IPython Development Team.
12 12 #
13 13 # Distributed under the terms of the Modified BSD License.
14 14 #
15 15 # The full license is in the file COPYING.txt, distributed with this software.
16 16 #-----------------------------------------------------------------------------
17 17
18 18 import io
19 19 import os, sys
20 20 import imp
21 21
22 22 try:
23 23 import hashlib
24 24 except ImportError:
25 25 import md5 as hashlib
26 26
27 27 from distutils.core import Distribution, Extension
28 28 from distutils.command.build_ext import build_ext
29 29
30 30 from IPython.core.magic import Magics, magics_class, cell_magic
31 31 from IPython.testing.skipdoctest import skip_doctest
32 32 from IPython.core.magic_arguments import (
33 33 argument, magic_arguments, parse_argstring
34 34 )
35 35 from IPython.utils import py3compat
36 36
37 37 import Cython
38 38 from Cython.Compiler.Errors import CompileError
39 39 from Cython.Compiler.Main import Context, default_options
40 40 from Cython.Build.Dependencies import cythonize
41 41
42 42
43 43 @magics_class
44 44 class CythonMagics(Magics):
45 45
46 46 def __init__(self, shell):
47 47 super(CythonMagics,self).__init__(shell)
48 48 self._reloads = {}
49 49 self._code_cache = {}
50 50
51 51 def _import_all(self, module):
52 52 for k,v in module.__dict__.items():
53 53 if not k.startswith('__'):
54 54 self.shell.push({k:v})
55 55
56 56 @cell_magic
57 57 def cython_inline(self, line, cell):
58 58 """Compile and run a Cython code cell using Cython.inline.
59 59
60 60 This magic simply passes the body of the cell to Cython.inline
61 61 and returns the result. If the variables `a` and `b` are defined
62 62 in the user's namespace, here is a simple example that returns
63 63 their sum::
64 64
65 65 %%cython_inline
66 66 return a+b
67 67
68 68 For most purposes, we recommend the usage of the `%%cython` magic.
69 69 """
70 70 locs = self.shell.user_global_ns
71 71 globs = self.shell.user_ns
72 72 return Cython.inline(cell, locals=locs, globals=globs)
73 73
74 74 @cell_magic
75 75 def cython_pyximport(self, line, cell):
76 76 """Compile and import a Cython code cell using pyximport.
77 77
78 78 The contents of the cell are written to a `.pyx` file in the current
79 79 working directory, which is then imported using `pyximport`. This
80 80 magic requires a module name to be passed::
81 81
82 82 %%cython_pyximport modulename
83 83 def f(x):
84 84 return 2.0*x
85 85
86 86 The compiled module is then imported and all of its symbols are injected into
87 87 the user's namespace. For most purposes, we recommend the usage of the
88 88 `%%cython` magic.
89 89 """
90 90 module_name = line.strip()
91 91 if not module_name:
92 92 raise ValueError('module name must be given')
93 93 fname = module_name + '.pyx'
94 94 with io.open(fname, 'w', encoding='utf-8') as f:
95 95 f.write(cell)
96 96 if 'pyximport' not in sys.modules:
97 97 import pyximport
98 98 pyximport.install(reload_support=True)
99 99 if module_name in self._reloads:
100 100 module = self._reloads[module_name]
101 101 reload(module)
102 102 else:
103 103 __import__(module_name)
104 104 module = sys.modules[module_name]
105 105 self._reloads[module_name] = module
106 106 self._import_all(module)
107 107
108 108 @magic_arguments()
109 109 @argument(
110 110 '-c', '--compile-args', action='append', default=[],
111 111 help="Extra flag to pass to compiler via the `extra_compile_args` Extension flag (can be called multiple times)."
112 112 )
113 113 @argument(
114 114 '-l', '--lib', action='append', default=[],
115 115 help="Add a library to link the extension against (can be called multiple times)."
116 116 )
117 117 @argument(
118 '-i', '--include', action='append', default=[],
118 '-I', '--include', action='append', default=[],
119 119 help="Add a path to the list of include directories (can be called multiple times)."
120 120 )
121 121 @argument(
122 122 '-f', '--force', action='store_true', default=False,
123 123 help="Force the compilation of the pyx module even if it hasn't changed"
124 124 )
125 125 @cell_magic
126 126 def cython(self, line, cell):
127 127 """Compile and import everything from a Cython code cell.
128 128
129 129 The contents of the cell are written to a `.pyx` file in the
130 130 directory `IPYTHONDIR/cython` using a filename with the hash of the code.
131 131 This file is then cythonized and compiled. The resulting module
132 132 is imported and all of its symbols are injected into the user's
133 133 namespace. The usage is similar to that of `%%cython_pyximport` but
134 134 you don't have to pass a module name::
135 135
136 136 %%cython
137 137 def f(x):
138 138 return 2.0*x
139 139 """
140 140 args = parse_argstring(self.cython, line)
141 141 code = cell if cell.endswith('\n') else cell+'\n'
142 142 lib_dir = os.path.join(self.shell.ipython_dir, 'cython')
143 143 cython_include_dirs = ['.']
144 144 force = args.force
145 145 quiet = True
146 146 ctx = Context(cython_include_dirs, default_options)
147 147 key = code, sys.version_info, sys.executable, Cython.__version__
148 148 module_name = "_cython_magic_" + hashlib.md5(str(key).encode('utf-8')).hexdigest()
149 149 so_ext = [ ext for ext,_,mod_type in imp.get_suffixes() if mod_type == imp.C_EXTENSION ][0]
150 150 module_path = os.path.join(lib_dir, module_name+so_ext)
151 151
152 152 if not os.path.exists(lib_dir):
153 153 os.makedirs(lib_dir)
154 154
155 155 if force or not os.path.isfile(module_path):
156 156 c_include_dirs = args.include
157 157 if 'numpy' in code:
158 158 import numpy
159 159 c_include_dirs.append(numpy.get_include())
160 160 pyx_file = os.path.join(lib_dir, module_name + '.pyx')
161 161 pyx_file = py3compat.cast_bytes_py2(pyx_file, encoding=sys.getfilesystemencoding())
162 162 with io.open(pyx_file, 'w', encoding='utf-8') as f:
163 163 f.write(code)
164 164 extension = Extension(
165 165 name = module_name,
166 166 sources = [pyx_file],
167 167 include_dirs = c_include_dirs,
168 168 extra_compile_args = args.compile_args,
169 169 libraries = args.lib,
170 170 )
171 171 dist = Distribution()
172 172 config_files = dist.find_config_files()
173 173 try:
174 174 config_files.remove('setup.cfg')
175 175 except ValueError:
176 176 pass
177 177 dist.parse_config_files(config_files)
178 178 build_extension = build_ext(dist)
179 179 build_extension.finalize_options()
180 180 try:
181 181 build_extension.extensions = cythonize([extension], ctx=ctx, quiet=quiet)
182 182 except CompileError:
183 183 return
184 184 build_extension.build_temp = os.path.dirname(pyx_file)
185 185 build_extension.build_lib = lib_dir
186 186 build_extension.run()
187 187 self._code_cache[key] = module_name
188 188
189 189 module = imp.load_dynamic(module_name, module_path)
190 190 self._import_all(module)
191 191
192 192
193 193 _loaded = False
194 194
195 195 def load_ipython_extension(ip):
196 196 """Load the extension in IPython."""
197 197 global _loaded
198 198 if not _loaded:
199 199 ip.register_magics(CythonMagics)
200 200 _loaded = True
@@ -1,239 +1,239 b''
1 1 {
2 2 "metadata": {
3 3 "name": "cython_extension"
4 4 },
5 5 "nbformat": 3,
6 6 "worksheets": [
7 7 {
8 8 "cells": [
9 9 {
10 10 "cell_type": "heading",
11 11 "level": 1,
12 12 "source": [
13 13 "Cython Magic Functions Extension"
14 14 ]
15 15 },
16 16 {
17 17 "cell_type": "heading",
18 18 "level": 2,
19 19 "source": [
20 20 "Loading the extension"
21 21 ]
22 22 },
23 23 {
24 24 "cell_type": "markdown",
25 25 "source": [
26 26 "IPtyhon has a `cythonmagic` extension that contains a number of magic functions for working with Cython code. This extension can be loaded using the `%load_ext` magic as follows:"
27 27 ]
28 28 },
29 29 {
30 30 "cell_type": "code",
31 31 "input": [
32 32 "%load_ext cythonmagic"
33 33 ],
34 34 "language": "python",
35 35 "outputs": [],
36 36 "prompt_number": 1
37 37 },
38 38 {
39 39 "cell_type": "heading",
40 40 "level": 2,
41 41 "source": [
42 42 "The %cython_inline magic"
43 43 ]
44 44 },
45 45 {
46 46 "cell_type": "markdown",
47 47 "source": [
48 48 "The `%%cython_inline` magic uses `Cython.inline` to compile a Cython expression. This allows you to enter and run a function body with Cython code. Use a bare `return` statement to return values. "
49 49 ]
50 50 },
51 51 {
52 52 "cell_type": "code",
53 53 "input": [
54 54 "a = 10\n",
55 55 "b = 20"
56 56 ],
57 57 "language": "python",
58 58 "outputs": [],
59 59 "prompt_number": 8
60 60 },
61 61 {
62 62 "cell_type": "code",
63 63 "input": [
64 64 "%%cython_inline\n",
65 65 "return a+b"
66 66 ],
67 67 "language": "python",
68 68 "outputs": [
69 69 {
70 70 "output_type": "pyout",
71 71 "prompt_number": 9,
72 72 "text": [
73 73 "30"
74 74 ]
75 75 }
76 76 ],
77 77 "prompt_number": 9
78 78 },
79 79 {
80 80 "cell_type": "heading",
81 81 "level": 2,
82 82 "source": [
83 83 "The %cython_pyximport magic"
84 84 ]
85 85 },
86 86 {
87 87 "cell_type": "markdown",
88 88 "source": [
89 89 "The `%%cython_pyximport` magic allows you to enter arbitrary Cython code into a cell. That Cython code is written as a `.pyx` file in the current working directory and then imported using `pyximport`. You have the specify the name of the module that the Code will appear in. All symbols from the module are imported automatically by the magic function."
90 90 ]
91 91 },
92 92 {
93 93 "cell_type": "code",
94 94 "input": [
95 95 "%%cython_pyximport foo\n",
96 96 "def f(x):\n",
97 97 " return 4.0*x"
98 98 ],
99 99 "language": "python",
100 100 "outputs": [],
101 101 "prompt_number": 18
102 102 },
103 103 {
104 104 "cell_type": "code",
105 105 "input": [
106 106 "f(10)"
107 107 ],
108 108 "language": "python",
109 109 "outputs": [
110 110 {
111 111 "output_type": "pyout",
112 112 "prompt_number": 19,
113 113 "text": [
114 114 "40.0"
115 115 ]
116 116 }
117 117 ],
118 118 "prompt_number": 19
119 119 },
120 120 {
121 121 "cell_type": "heading",
122 122 "level": 2,
123 123 "source": [
124 124 "The %cython magic"
125 125 ]
126 126 },
127 127 {
128 128 "cell_type": "markdown",
129 129 "source": [
130 130 "Probably the most important magic is the `%cython` magic. This is similar to the `%%cython_pyximport` magic, but doesn't require you to specify a module name. Instead, the `%%cython` magic uses manages everything using temporary files in the `~/.cython/magic` directory. All of the symbols in the Cython module are imported automatically by the magic.\n",
131 131 "\n",
132 132 "Here is a simple example of a Black-Scholes options pricing algorithm written in Cython:"
133 133 ]
134 134 },
135 135 {
136 136 "cell_type": "code",
137 137 "input": [
138 138 "%%cython\n",
139 139 "cimport cython\n",
140 140 "from libc.math cimport exp, sqrt, pow, log, erf\n",
141 141 "\n",
142 142 "@cython.cdivision(True)\n",
143 143 "cdef double std_norm_cdf(double x) nogil:\n",
144 144 " return 0.5*(1+erf(x/sqrt(2.0)))\n",
145 145 "\n",
146 146 "@cython.cdivision(True)\n",
147 147 "def black_scholes(double s, double k, double t, double v,\n",
148 148 " double rf, double div, double cp):\n",
149 149 " \"\"\"Price an option using the Black-Scholes model.\n",
150 150 " \n",
151 151 " s : initial stock price\n",
152 152 " k : strike price\n",
153 153 " t : expiration time\n",
154 154 " v : volatility\n",
155 155 " rf : risk-free rate\n",
156 156 " div : dividend\n",
157 157 " cp : +1/-1 for call/put\n",
158 158 " \"\"\"\n",
159 159 " cdef double d1, d2, optprice\n",
160 160 " with nogil:\n",
161 161 " d1 = (log(s/k)+(rf-div+0.5*pow(v,2))*t)/(v*sqrt(t))\n",
162 162 " d2 = d1 - v*sqrt(t)\n",
163 163 " optprice = cp*s*exp(-div*t)*std_norm_cdf(cp*d1) - \\\n",
164 164 " cp*k*exp(-rf*t)*std_norm_cdf(cp*d2)\n",
165 165 " return optprice"
166 166 ],
167 167 "language": "python",
168 168 "outputs": [],
169 169 "prompt_number": 6
170 170 },
171 171 {
172 172 "cell_type": "code",
173 173 "input": [
174 174 "black_scholes(100.0, 100.0, 1.0, 0.3, 0.03, 0.0, -1)"
175 175 ],
176 176 "language": "python",
177 177 "outputs": [
178 178 {
179 179 "output_type": "pyout",
180 180 "prompt_number": 7,
181 181 "text": [
182 182 "10.327861752731728"
183 183 ]
184 184 }
185 185 ],
186 186 "prompt_number": 7
187 187 },
188 188 {
189 189 "cell_type": "code",
190 190 "input": [
191 191 "%timeit black_scholes(100.0, 100.0, 1.0, 0.3, 0.03, 0.0, -1)"
192 192 ],
193 193 "language": "python",
194 194 "outputs": [
195 195 {
196 196 "output_type": "stream",
197 197 "stream": "stdout",
198 198 "text": [
199 199 "1000000 loops, best of 3: 621 ns per loop\n"
200 200 ]
201 201 }
202 202 ],
203 203 "prompt_number": 14
204 204 },
205 205 {
206 206 "cell_type": "markdown",
207 207 "source": [
208 "Cython allows you to specify additional libraries to be linked with your extension, you can do so with the `-l` flag (also spelled `--lib`). Note that this flag can be passed more than once to specify multiple libraries, such as `-l lib1 -l lib2`. Here's a simple example of how to access the system math library:"
208 "Cython allows you to specify additional libraries to be linked with your extension, you can do so with the `-l` flag (also spelled `--lib`). Note that this flag can be passed more than once to specify multiple libraries, such as `-lm -llib2 --lib lib3`. Here's a simple example of how to access the system math library:"
209 209 ]
210 210 },
211 211 {
212 212 "cell_type": "code",
213 213 "input": [
214 "%%cython -l m\n",
214 "%%cython -lm\n",
215 215 "from libc.math cimport sin\n",
216 216 "print 'sin(1)=', sin(1)"
217 217 ],
218 218 "language": "python",
219 219 "outputs": [
220 220 {
221 221 "output_type": "stream",
222 222 "stream": "stdout",
223 223 "text": [
224 224 "sin(1)= 0.841470984808\n"
225 225 ]
226 226 }
227 227 ],
228 228 "prompt_number": 2
229 229 },
230 230 {
231 231 "cell_type": "markdown",
232 232 "source": [
233 "You can similarly use the `-i/--include` flag to add include directories to the search path, and `-c/--compile-args` to add extra flags that are passed to Cython via the `extra_compile_args` of the distutils `Extension` class. Please see [the Cython docs on C library usage](http://docs.cython.org/src/tutorial/clibraries.html) for more details on the use of these flags."
233 "You can similarly use the `-I/--include` flag to add include directories to the search path, and `-c/--compile-args` to add extra flags that are passed to Cython via the `extra_compile_args` of the distutils `Extension` class. Please see [the Cython docs on C library usage](http://docs.cython.org/src/tutorial/clibraries.html) for more details on the use of these flags."
234 234 ]
235 235 }
236 236 ]
237 237 }
238 238 ]
239 239 } No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now