##// END OF EJS Templates
Fixed a vcvarsall.bat error on win32/Py2.7 when trying to compile with mingw.
David Hirschfeld -
Show More
@@ -1,181 +1,188 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 from importlib import import_module
21 21 import imp
22 22
23 23 try:
24 24 import hashlib
25 25 except ImportError:
26 26 import md5 as hashlib
27 27
28 28 from distutils.core import Distribution, Extension
29 29 from distutils.command.build_ext import build_ext
30 30
31 31 from IPython.core.magic import Magics, magics_class, cell_magic
32 32 from IPython.testing.skipdoctest import skip_doctest
33 33 from IPython.core.magic_arguments import (
34 34 argument, magic_arguments, parse_argstring
35 35 )
36 36 from IPython.utils import py3compat
37 37
38 38 import Cython
39 39 from Cython.Compiler.Errors import CompileError
40 40 from Cython.Compiler.Main import Context, default_options
41 41 from Cython.Build.Dependencies import cythonize
42 42
43 43
44 44 @magics_class
45 45 class CythonMagics(Magics):
46 46
47 47 def __init__(self, shell):
48 48 super(CythonMagics,self).__init__(shell)
49 49 self._reloads = {}
50 50 self._code_cache = {}
51 51
52 52 def _import_all(self, module):
53 53 for k,v in module.__dict__.items():
54 54 if not k.startswith('__'):
55 55 self.shell.push({k:v})
56 56
57 57 @cell_magic
58 58 def cython_inline(self, line, cell):
59 59 """Compile and run a Cython code cell using Cython.inline.
60 60
61 61 This magic simply passes the body of the cell to Cython.inline
62 62 and returns the result. If the variables `a` and `b` are defined
63 63 in the user's namespace, here is a simple example that returns
64 64 their sum::
65 65
66 66 %%cython_inline
67 67 return a+b
68 68
69 69 For most purposes, we recommend the usage of the `%%cython` magic.
70 70 """
71 71 locs = self.shell.user_global_ns
72 72 globs = self.shell.user_ns
73 73 return Cython.inline(cell, locals=locs, globals=globs)
74 74
75 75 @cell_magic
76 76 def cython_pyximport(self, line, cell):
77 77 """Compile and import a Cython code cell using pyximport.
78 78
79 79 The contents of the cell are written to a `.pyx` file in the current
80 80 working directory, which is then imported using `pyximport`. This
81 81 magic requires a module name to be passed::
82 82
83 83 %%cython_pyximport modulename
84 84 def f(x):
85 85 return 2.0*x
86 86
87 87 The compiled module is then imported and all of its symbols are injected into
88 88 the user's namespace. For most purposes, we recommend the usage of the
89 89 `%%cython` magic.
90 90 """
91 91 module_name = line.strip()
92 92 if not module_name:
93 93 raise ValueError('module name must be given')
94 94 fname = module_name + '.pyx'
95 95 with io.open(fname, 'w', encoding='utf-8') as f:
96 96 f.write(cell)
97 97 if 'pyximport' not in sys.modules:
98 98 import pyximport
99 99 pyximport.install(reload_support=True)
100 100 if module_name in self._reloads:
101 101 module = self._reloads[module_name]
102 102 reload(module)
103 103 else:
104 104 module = import_module(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 '-f', '--force', action='store_true', default=False,
111 111 help="Force the compilation of the pyx module even if it hasn't changed"
112 112 )
113 113 @cell_magic
114 114 def cython(self, line, cell):
115 115 """Compile and import everything from a Cython code cell.
116 116
117 117 The contents of the cell are written to a `.pyx` file in the
118 118 directory `IPYTHONDIR/cython` using a filename with the hash of the code.
119 119 This file is then cythonized and compiled. The resulting module
120 120 is imported and all of its symbols are injected into the user's
121 121 namespace. The usage is similar to that of `%%cython_pyximport` but
122 122 you don't have to pass a module name::
123 123
124 124 %%cython
125 125 def f(x):
126 126 return 2.0*x
127 127 """
128 128 args = parse_argstring(self.cython, line)
129 129 code = cell if cell.endswith('\n') else cell+'\n'
130 130 lib_dir=os.path.join(self.shell.ipython_dir, 'cython')
131 131 cython_include_dirs=['.']
132 132 force=args.force
133 133 quiet=True
134 134 ctx = Context(cython_include_dirs, default_options)
135 135 key = code, sys.version_info, sys.executable, Cython.__version__
136 136 module_name = "_cython_magic_" + hashlib.md5(str(key).encode('utf-8')).hexdigest()
137 137 so_ext = [ ext for ext,_,mod_type in imp.get_suffixes() if mod_type == imp.C_EXTENSION ][0]
138 138 module_path = os.path.join(lib_dir, module_name+so_ext)
139 139
140 140 if not os.path.exists(lib_dir):
141 141 os.makedirs(lib_dir)
142 142
143 143 if force or not os.path.isfile(module_path):
144 144 cflags = []
145 145 c_include_dirs = []
146 146 if 'numpy' in code:
147 147 import numpy
148 148 c_include_dirs.append(numpy.get_include())
149 149 pyx_file = os.path.join(lib_dir, module_name + '.pyx')
150 150 pyx_file = py3compat.unicode_to_str(pyx_file, encoding=sys.getfilesystemencoding())
151 151 with io.open(pyx_file, 'w', encoding='utf-8') as f:
152 152 f.write(code)
153 153 extension = Extension(
154 154 name = module_name,
155 155 sources = [pyx_file],
156 156 include_dirs = c_include_dirs,
157 157 extra_compile_args = cflags
158 158 )
159 build_extension = build_ext(Distribution())
159 dist = Distribution()
160 config_files = dist.find_config_files()
161 try:
162 config_files.remove('setup.cfg')
163 except ValueError:
164 pass
165 dist.parse_config_files(config_files)
166 build_extension = build_ext(dist)
160 167 build_extension.finalize_options()
161 168 try:
162 169 build_extension.extensions = cythonize([extension], ctx=ctx, quiet=quiet)
163 170 except CompileError:
164 171 return
165 172 build_extension.build_temp = os.path.dirname(pyx_file)
166 173 build_extension.build_lib = lib_dir
167 174 build_extension.run()
168 175 self._code_cache[key] = module_name
169 176
170 177 module = imp.load_dynamic(module_name, module_path)
171 178 self._import_all(module)
172 179
173 180
174 181 _loaded = False
175 182
176 183 def load_ipython_extension(ip):
177 184 """Load the extension in IPython."""
178 185 global _loaded
179 186 if not _loaded:
180 187 ip.register_magics(CythonMagics)
181 188 _loaded = True
General Comments 0
You need to be logged in to leave comments. Login now