Hi all,
I am using cython and numpy and looked for a way to get cython modules
using numpy compiled with pyximport.
I found on the list the following message
(http://codespeak.net/pipermail/cython-dev/2009-May/005289.html)
but didn't find any modification in the cython repository in this
direction.
Following Lisandro DalcĂn's suggestion, I made a patch that adds a
ext_opts option to pyximport.install() which cascades to
pyximport.get_distutils_extension() and is used as a dictionnary with
options for distutils.Extension().
Only the dictionnary type is tested (I assume Extension will tell if an
option is not good).
I also added a pyximport.unsinstall() function (so it's possible to
change options of the importer).
Example:
In [1]: import pyximport2
In [2]: import numpy
In [3]: pyximport2.install(ext_opts={'include_dirs':
[numpy.get_include()]})
In [4]: import test
In [5]: test.total([1,2,3,4,5])
Out[5]: 15.0
I would be happy if something like this could be included in cython !
Please tell me what you think.
Cheers,
Cyrille Rosset.
diff -Naur pyximport/pyximport.py pyximport2/pyximport.py
--- pyximport/pyximport.py 2009-07-31 18:27:51.987035982 +0200
+++ pyximport2/pyximport.py 2009-07-31 17:43:35.760613357 +0200
@@ -63,12 +63,17 @@
def _load_pyrex(name, filename):
"Load a pyrex file given a name and filename."
-def get_distutils_extension(modname, pyxfilename):
+def get_distutils_extension(modname, pyxfilename,ext_opts=None):
extra = "_" + hashlib.md5(open(pyxfilename).read()).hexdigest()
# modname = modname + extra
extension_mod = handle_special_build(modname, pyxfilename)
if not extension_mod:
- extension_mod = Extension(name = modname, sources=[pyxfilename])
+ if ext_opts is None:
+ ext_opts = {}
+ assert isinstance(ext_opts,dict), ("ext_opts must be a dictionnary"
+ " or None")
+ extension_mod = Extension(name = modname, sources=[pyxfilename],
+ **ext_opts)
return extension_mod
def handle_special_build(modname, pyxfilename):
@@ -122,12 +127,13 @@
os.utime(pyxfilename, (filetime, filetime))
_test_files.append(file)
-def build_module(name, pyxfilename, pyxbuild_dir=None):
+def build_module(name, pyxfilename, pyxbuild_dir=None, ext_opts=None):
assert os.path.exists(pyxfilename), (
"Path does not exist: %s" % pyxfilename)
handle_dependencies(pyxfilename)
- extension_mod = get_distutils_extension(name, pyxfilename)
+ extension_mod = get_distutils_extension(name, pyxfilename,
+ ext_opts=ext_opts)
so_path = pyxbuild.pyx_to_dll(pyxfilename, extension_mod,
build_in_temp=True,
@@ -145,9 +151,9 @@
return so_path
-def load_module(name, pyxfilename, pyxbuild_dir=None):
+def load_module(name, pyxfilename, pyxbuild_dir=None, ext_opts=None):
try:
- so_path = build_module(name, pyxfilename, pyxbuild_dir)
+ so_path = build_module(name, pyxfilename, pyxbuild_dir, ext_opts)
mod = imp.load_dynamic(name, so_path)
assert mod.__file__ == so_path, (mod.__file__, so_path)
except Exception, e:
@@ -160,9 +166,10 @@
class PyxImporter(object):
"""A meta-path importer for .pyx files.
"""
- def __init__(self, extension=PYX_EXT, pyxbuild_dir=None):
+ def __init__(self, extension=PYX_EXT, pyxbuild_dir=None, ext_opts=None):
self.extension = extension
self.pyxbuild_dir = pyxbuild_dir
+ self.ext_opts = ext_opts
def find_module(self, fullname, package_path=None):
if fullname in sys.modules:
@@ -197,14 +204,16 @@
for filename in os.listdir(path):
if filename == pyx_module_name:
return PyxLoader(fullname, join_path(path, filename),
- pyxbuild_dir=self.pyxbuild_dir)
+ pyxbuild_dir=self.pyxbuild_dir,
+ ext_opts=self.ext_opts)
elif filename == module_name:
package_path = join_path(path, filename)
init_path = join_path(package_path,
'__init__' + self.extension)
if is_file(init_path):
return PyxLoader(fullname, package_path, init_path,
- pyxbuild_dir=self.pyxbuild_dir)
+ pyxbuild_dir=self.pyxbuild_dir,
+ ext_opts=self.ext_opts)
# not found, normal package, not a .pyx file, none of our business
return None
@@ -267,10 +276,12 @@
return importer
class PyxLoader(object):
- def __init__(self, fullname, path, init_path=None, pyxbuild_dir=None):
+ def __init__(self, fullname, path, init_path=None, pyxbuild_dir=None,
+ ext_opts=None):
self.fullname = fullname
self.path, self.init_path = path, init_path
self.pyxbuild_dir = pyxbuild_dir
+ self.ext_opts = ext_opts
def load_module(self, fullname):
assert self.fullname == fullname, (
@@ -280,16 +291,16 @@
# package
#print "PACKAGE", fullname
module = load_module(fullname, self.init_path,
- self.pyxbuild_dir)
+ self.pyxbuild_dir, self.ext_opts)
module.__path__ = [self.path]
else:
#print "MODULE", fullname
module = load_module(fullname, self.path,
- self.pyxbuild_dir)
+ self.pyxbuild_dir, self.ext_opts)
return module
-def install(pyximport=True, pyimport=False, build_dir=None):
+def install(pyximport=True, pyimport=False, build_dir=None, ext_opts=None):
"""Main entry point. Call this to install the .pyx import hook in
your meta-path for a single Python process. If you want it to be
installed whenever you use Python, add it to your sitecustomize
@@ -321,9 +332,17 @@
sys.meta_path.insert(0, importer)
if pyximport and not has_pyx_importer:
- importer = PyxImporter(pyxbuild_dir=build_dir)
+ importer = PyxImporter(pyxbuild_dir=build_dir,ext_opts=ext_opts)
sys.meta_path.append(importer)
+def uninstall():
+ """Uninstall any PyxImporter/PyImporter installed
+ """
+ to_remove = [ importer for importer in sys.meta_path
+ if isinstance(importer,PyxImporter) ]
+ for pyximporter in to_remove:
+ sys.meta_path.remove(pyximporter)
+ print "Removed %d PyxImporter's"%(len(to_remove))
# MAIN
_______________________________________________
Cython-dev mailing list
[email protected]
http://codespeak.net/mailman/listinfo/cython-dev