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

Reply via email to