##// END OF EJS Templates
Backport PR #3013: py3 workaround for reload in cythonmagic...
Backport PR #3013: py3 workaround for reload in cythonmagic closes #3007

File last commit:

r9976:ddddf17a
r9976:ddddf17a
Show More
cythonmagic.py
205 lines | 7.1 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
import imp
try:
MinRK
Backport PR #3013: py3 workaround for reload in cythonmagic...
r9976 reload
except NameError: # Python 3
from imp import reload
try:
Brian Granger
Adding Cython extension and example notebook.
r7031 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:
Bradley M. Froehle
Remove importlib dependency which not available in Python 2.6....
r7342 __import__(module_name)
module = sys.modules[module_name]
Brian Granger
Adding Cython extension and example notebook.
r7031 self._reloads[module_name] = module
self._import_all(module)
@magic_arguments()
@argument(
Fernando Perez
Add support for libraries, include path and compiler args to %%cython...
r7419 '-c', '--compile-args', action='append', default=[],
Fernando Perez
Fix language in docstrings as per review.
r7426 help="Extra flags to pass to compiler via the `extra_compile_args` Extension flag (can be specified multiple times)."
Fernando Perez
Add support for libraries, include path and compiler args to %%cython...
r7419 )
@argument(
'-l', '--lib', action='append', default=[],
Fernando Perez
Fix language in docstrings as per review.
r7426 help="Add a library to link the extension against (can be specified multiple times)."
Fernando Perez
Add support for libraries, include path and compiler args to %%cython...
r7419 )
@argument(
Fernando Perez
Use -I (capital) to match gcc stle and show -l usage without spaces.
r7422 '-I', '--include', action='append', default=[],
Fernando Perez
Fix language in docstrings as per review.
r7426 help="Add a path to the list of include directories (can be specified multiple times)."
Fernando Perez
Add support for libraries, include path and compiler args to %%cython...
r7419 )
@argument(
Brian Granger
Adding Cython extension and example notebook.
r7031 '-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'
Fernando Perez
Add support for libraries, include path and compiler args to %%cython...
r7419 lib_dir = os.path.join(self.shell.ipython_dir, 'cython')
cython_include_dirs = ['.']
force = args.force
quiet = True
Brian Granger
Adding Cython extension and example notebook.
r7031 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):
Fernando Perez
Add support for libraries, include path and compiler args to %%cython...
r7419 c_include_dirs = args.include
Brian Granger
Adding Cython extension and example notebook.
r7031 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,
Fernando Perez
Add support for libraries, include path and compiler args to %%cython...
r7419 extra_compile_args = args.compile_args,
libraries = args.lib,
Brian Granger
Adding Cython extension and example notebook.
r7031 )
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