##// END OF EJS Templates
bracket on same line
bracket on same line

File last commit:

r7114:a1fcd080 merge
r7293:d7631d07
Show More
cythonmagic.py
188 lines | 6.4 KiB | text/x-python | PythonLexer
Brian Granger
Adding Cython extension and example notebook.
r7031 # -*- coding: utf-8 -*-
"""
Cython related magics.
Author:
* Brian Granger
Parts of this code were taken from Cython.inline.
"""
#-----------------------------------------------------------------------------
# Copyright (C) 2010-2011, IPython Development Team.
#
# Distributed under the terms of the Modified BSD License.
#
# The full license is in the file COPYING.txt, distributed with this software.
#-----------------------------------------------------------------------------
Brian Granger
More code review changes:...
r7102 import io
Brian Granger
Adding Cython extension and example notebook.
r7031 import os, sys
from importlib import import_module
import imp
try:
import hashlib
except ImportError:
import md5 as hashlib
from distutils.core import Distribution, Extension
from distutils.command.build_ext import build_ext
from IPython.core.magic import Magics, magics_class, cell_magic
from IPython.testing.skipdoctest import skip_doctest
from IPython.core.magic_arguments import (
argument, magic_arguments, parse_argstring
)
Brian Granger
More code review changes:...
r7102 from IPython.utils import py3compat
Brian Granger
Adding Cython extension and example notebook.
r7031
import Cython
from Cython.Compiler.Errors import CompileError
from Cython.Compiler.Main import Context, default_options
from Cython.Build.Dependencies import cythonize
@magics_class
class CythonMagics(Magics):
def __init__(self, shell):
super(CythonMagics,self).__init__(shell)
self._reloads = {}
self._code_cache = {}
def _import_all(self, module):
for k,v in module.__dict__.items():
if not k.startswith('__'):
self.shell.push({k:v})
@cell_magic
def cython_inline(self, line, cell):
Brian Granger
Adding docstrings to the cython magics.
r7037 """Compile and run a Cython code cell using Cython.inline.
This magic simply passes the body of the cell to Cython.inline
and returns the result. If the variables `a` and `b` are defined
in the user's namespace, here is a simple example that returns
their sum::
%%cython_inline
return a+b
For most purposes, we recommend the usage of the `%%cython` magic.
"""
Brian Granger
Adding Cython extension and example notebook.
r7031 locs = self.shell.user_global_ns
globs = self.shell.user_ns
return Cython.inline(cell, locals=locs, globals=globs)
@cell_magic
def cython_pyximport(self, line, cell):
Brian Granger
Adding docstrings to the cython magics.
r7037 """Compile and import a Cython code cell using pyximport.
The contents of the cell are written to a `.pyx` file in the current
working directory, which is then imported using `pyximport`. This
magic requires a module name to be passed::
%%cython_pyximport modulename
def f(x):
return 2.0*x
The compiled module is then imported and all of its symbols are injected into
the user's namespace. For most purposes, we recommend the usage of the
`%%cython` magic.
"""
Brian Granger
Adding Cython extension and example notebook.
r7031 module_name = line.strip()
if not module_name:
raise ValueError('module name must be given')
fname = module_name + '.pyx'
Brian Granger
More code review changes:...
r7102 with io.open(fname, 'w', encoding='utf-8') as f:
Brian Granger
Adding Cython extension and example notebook.
r7031 f.write(cell)
if 'pyximport' not in sys.modules:
import pyximport
pyximport.install(reload_support=True)
if module_name in self._reloads:
module = self._reloads[module_name]
reload(module)
else:
module = import_module(module_name)
self._reloads[module_name] = module
self._import_all(module)
@magic_arguments()
@argument(
'-f', '--force', action='store_true', default=False,
help="Force the compilation of the pyx module even if it hasn't changed"
)
@cell_magic
def cython(self, line, cell):
Brian Granger
Adding docstrings to the cython magics.
r7037 """Compile and import everything from a Cython code cell.
The contents of the cell are written to a `.pyx` file in the
Brian Granger
Changes to address code review:...
r7100 directory `IPYTHONDIR/cython` using a filename with the hash of the code.
Brian Granger
Adding docstrings to the cython magics.
r7037 This file is then cythonized and compiled. The resulting module
is imported and all of its symbols are injected into the user's
namespace. The usage is similar to that of `%%cython_pyximport` but
you don't have to pass a module name::
%%cython
def f(x):
return 2.0*x
"""
Brian Granger
Adding Cython extension and example notebook.
r7031 args = parse_argstring(self.cython, line)
code = cell if cell.endswith('\n') else cell+'\n'
Brian Granger
More code review changes:...
r7102 lib_dir=os.path.join(self.shell.ipython_dir, 'cython')
Brian Granger
Adding Cython extension and example notebook.
r7031 cython_include_dirs=['.']
force=args.force
quiet=True
ctx = Context(cython_include_dirs, default_options)
key = code, sys.version_info, sys.executable, Cython.__version__
module_name = "_cython_magic_" + hashlib.md5(str(key).encode('utf-8')).hexdigest()
so_ext = [ ext for ext,_,mod_type in imp.get_suffixes() if mod_type == imp.C_EXTENSION ][0]
module_path = os.path.join(lib_dir, module_name+so_ext)
if not os.path.exists(lib_dir):
os.makedirs(lib_dir)
if force or not os.path.isfile(module_path):
cflags = []
c_include_dirs = []
if 'numpy' in code:
import numpy
c_include_dirs.append(numpy.get_include())
pyx_file = os.path.join(lib_dir, module_name + '.pyx')
Thomas Kluyver
Use py3compat.cast_bytes_py2 in cythonmagic extension.
r7113 pyx_file = py3compat.cast_bytes_py2(pyx_file, encoding=sys.getfilesystemencoding())
Brian Granger
More code review changes:...
r7102 with io.open(pyx_file, 'w', encoding='utf-8') as f:
Brian Granger
Adding Cython extension and example notebook.
r7031 f.write(code)
extension = Extension(
name = module_name,
sources = [pyx_file],
include_dirs = c_include_dirs,
extra_compile_args = cflags
)
David Hirschfeld
Fixed a vcvarsall.bat error on win32/Py2.7 when trying to compile with mingw.
r7111 dist = Distribution()
config_files = dist.find_config_files()
try:
config_files.remove('setup.cfg')
except ValueError:
pass
dist.parse_config_files(config_files)
build_extension = build_ext(dist)
Brian Granger
Adding Cython extension and example notebook.
r7031 build_extension.finalize_options()
try:
build_extension.extensions = cythonize([extension], ctx=ctx, quiet=quiet)
except CompileError:
return
build_extension.build_temp = os.path.dirname(pyx_file)
build_extension.build_lib = lib_dir
build_extension.run()
self._code_cache[key] = module_name
module = imp.load_dynamic(module_name, module_path)
self._import_all(module)
_loaded = False
def load_ipython_extension(ip):
"""Load the extension in IPython."""
global _loaded
if not _loaded:
ip.register_magics(CythonMagics)
_loaded = True