Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Labels
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Commits
Open sidebar
nexedi
cython
Commits
36eefe00
Commit
36eefe00
authored
Jan 24, 2009
by
Stefan Behnel
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
support for pyximporting .py files
parent
0a00f725
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
134 additions
and
27 deletions
+134
-27
pyximport/pyxbuild.py
pyximport/pyxbuild.py
+9
-3
pyximport/pyximport.py
pyximport/pyximport.py
+125
-24
No files found.
pyximport/pyxbuild.py
View file @
36eefe00
...
@@ -14,7 +14,8 @@ from Cython.Distutils import build_ext
...
@@ -14,7 +14,8 @@ from Cython.Distutils import build_ext
import
shutil
import
shutil
DEBUG
=
0
DEBUG
=
0
def
pyx_to_dll
(
filename
,
ext
=
None
,
force_rebuild
=
0
):
def
pyx_to_dll
(
filename
,
ext
=
None
,
force_rebuild
=
0
,
build_in_temp
=
False
,
pyxbuild_dir
=
None
):
"""Compile a PYX file to a DLL and return the name of the generated .so
"""Compile a PYX file to a DLL and return the name of the generated .so
or .dll ."""
or .dll ."""
assert
os
.
path
.
exists
(
filename
)
assert
os
.
path
.
exists
(
filename
)
...
@@ -26,6 +27,9 @@ def pyx_to_dll(filename, ext = None, force_rebuild = 0):
...
@@ -26,6 +27,9 @@ def pyx_to_dll(filename, ext = None, force_rebuild = 0):
assert
extension
in
(
".pyx"
,
".py"
),
extension
assert
extension
in
(
".pyx"
,
".py"
),
extension
ext
=
Extension
(
name
=
modname
,
sources
=
[
filename
])
ext
=
Extension
(
name
=
modname
,
sources
=
[
filename
])
if
not
pyxbuild_dir
:
pyxbuild_dir
=
os
.
path
.
join
(
path
,
"_pyxbld"
)
if
DEBUG
:
if
DEBUG
:
quiet
=
"--verbose"
quiet
=
"--verbose"
else
:
else
:
...
@@ -33,13 +37,15 @@ def pyx_to_dll(filename, ext = None, force_rebuild = 0):
...
@@ -33,13 +37,15 @@ def pyx_to_dll(filename, ext = None, force_rebuild = 0):
args
=
[
quiet
,
"build_ext"
]
args
=
[
quiet
,
"build_ext"
]
if
force_rebuild
:
if
force_rebuild
:
args
.
append
(
"--force"
)
args
.
append
(
"--force"
)
if
build_in_temp
:
args
.
append
(
"--pyrex-c-in-temp"
)
dist
=
Distribution
({
"script_name"
:
None
,
"script_args"
:
args
})
dist
=
Distribution
({
"script_name"
:
None
,
"script_args"
:
args
})
if
not
dist
.
ext_modules
:
if
not
dist
.
ext_modules
:
dist
.
ext_modules
=
[]
dist
.
ext_modules
=
[]
dist
.
ext_modules
.
append
(
ext
)
dist
.
ext_modules
.
append
(
ext
)
dist
.
cmdclass
=
{
'build_ext'
:
build_ext
}
dist
.
cmdclass
=
{
'build_ext'
:
build_ext
}
build
=
dist
.
get_command_obj
(
'build'
)
build
=
dist
.
get_command_obj
(
'build'
)
build
.
build_base
=
os
.
path
.
join
(
path
,
"_pyxbld"
)
build
.
build_base
=
pyxbuild_dir
try
:
try
:
ok
=
dist
.
parse_command_line
()
ok
=
dist
.
parse_command_line
()
...
@@ -71,7 +77,7 @@ def pyx_to_dll(filename, ext = None, force_rebuild = 0):
...
@@ -71,7 +77,7 @@ def pyx_to_dll(filename, ext = None, force_rebuild = 0):
if
DEBUG
:
if
DEBUG
:
raise
raise
else
:
else
:
raise
RuntimeError
,
"error: "
+
str
(
msg
)
raise
RuntimeError
(
repr
(
msg
)
)
if
__name__
==
"__main__"
:
if
__name__
==
"__main__"
:
pyx_to_dll
(
"dummy.pyx"
)
pyx_to_dll
(
"dummy.pyx"
)
...
...
pyximport/pyximport.py
View file @
36eefe00
...
@@ -40,6 +40,8 @@ PYX_EXT = ".pyx"
...
@@ -40,6 +40,8 @@ PYX_EXT = ".pyx"
PYXDEP_EXT
=
".pyxdep"
PYXDEP_EXT
=
".pyxdep"
PYXBLD_EXT
=
".pyxbld"
PYXBLD_EXT
=
".pyxbld"
DEBUG_IMPORT
=
False
# Performance problem: for every PYX file that is imported, we will
# Performance problem: for every PYX file that is imported, we will
# invoke the whole distutils infrastructure even if the module is
# invoke the whole distutils infrastructure even if the module is
# already built. It might be more efficient to only do it when the
# already built. It might be more efficient to only do it when the
...
@@ -109,14 +111,16 @@ def handle_dependencies(pyxfilename):
...
@@ -109,14 +111,16 @@ def handle_dependencies(pyxfilename):
os
.
utime
(
pyxfilename
,
(
filetime
,
filetime
))
os
.
utime
(
pyxfilename
,
(
filetime
,
filetime
))
_test_files
.
append
(
file
)
_test_files
.
append
(
file
)
def
build_module
(
name
,
pyxfilename
):
def
build_module
(
name
,
pyxfilename
,
pyxbuild_dir
=
None
):
assert
os
.
path
.
exists
(
pyxfilename
),
(
assert
os
.
path
.
exists
(
pyxfilename
),
(
"Path does not exist: %s"
%
pyxfilename
)
"Path does not exist: %s"
%
pyxfilename
)
handle_dependencies
(
pyxfilename
)
handle_dependencies
(
pyxfilename
)
extension_mod
=
get_distutils_extension
(
name
,
pyxfilename
)
extension_mod
=
get_distutils_extension
(
name
,
pyxfilename
)
so_path
=
pyxbuild
.
pyx_to_dll
(
pyxfilename
,
extension_mod
)
so_path
=
pyxbuild
.
pyx_to_dll
(
pyxfilename
,
extension_mod
,
build_in_temp
=
True
,
pyxbuild_dir
=
pyxbuild_dir
)
assert
os
.
path
.
exists
(
so_path
),
"Cannot find: %s"
%
so_path
assert
os
.
path
.
exists
(
so_path
),
"Cannot find: %s"
%
so_path
junkpath
=
os
.
path
.
join
(
os
.
path
.
dirname
(
so_path
),
name
+
"_*"
)
junkpath
=
os
.
path
.
join
(
os
.
path
.
dirname
(
so_path
),
name
+
"_*"
)
...
@@ -130,21 +134,30 @@ def build_module(name, pyxfilename):
...
@@ -130,21 +134,30 @@ def build_module(name, pyxfilename):
return
so_path
return
so_path
def
load_module
(
name
,
pyxfilename
):
def
load_module
(
name
,
pyxfilename
,
pyxbuild_dir
=
None
):
so_path
=
build_module
(
name
,
pyxfilename
)
try
:
mod
=
imp
.
load_dynamic
(
name
,
so_path
)
so_path
=
build_module
(
name
,
pyxfilename
,
pyxbuild_dir
)
assert
mod
.
__file__
==
so_path
,
(
mod
.
__file__
,
so_path
)
mod
=
imp
.
load_dynamic
(
name
,
so_path
)
assert
mod
.
__file__
==
so_path
,
(
mod
.
__file__
,
so_path
)
except
Exception
,
e
:
raise
ImportError
(
"Building module failed: %s"
%
e
)
return
mod
return
mod
# import hooks
# import hooks
class
PyxImporter
(
object
):
class
PyxImporter
(
object
):
def
__init__
(
self
):
"""A meta-path importer for .pyx files.
pass
"""
def
__init__
(
self
,
extension
=
PYX_EXT
,
pyxbuild_dir
=
None
):
self
.
extension
=
extension
self
.
pyxbuild_dir
=
pyxbuild_dir
def
find_module
(
self
,
fullname
,
package_path
=
None
):
def
find_module
(
self
,
fullname
,
package_path
=
None
):
#print "SEARCHING", fullname, package_path
if
fullname
in
sys
.
modules
:
return
None
if
DEBUG_IMPORT
:
print
"SEARCHING"
,
fullname
,
package_path
if
'.'
in
fullname
:
if
'.'
in
fullname
:
mod_parts
=
fullname
.
split
(
'.'
)
mod_parts
=
fullname
.
split
(
'.'
)
package
=
'.'
.
join
(
mod_parts
[:
-
1
])
package
=
'.'
.
join
(
mod_parts
[:
-
1
])
...
@@ -152,7 +165,7 @@ class PyxImporter(object):
...
@@ -152,7 +165,7 @@ class PyxImporter(object):
else
:
else
:
package
=
None
package
=
None
module_name
=
fullname
module_name
=
fullname
pyx_module_name
=
module_name
+
PYX_EXT
pyx_module_name
=
module_name
+
self
.
extension
# this may work, but it returns the file content, not its path
# this may work, but it returns the file content, not its path
#import pkgutil
#import pkgutil
#pyx_source = pkgutil.get_data(package, pyx_module_name)
#pyx_source = pkgutil.get_data(package, pyx_module_name)
...
@@ -166,18 +179,81 @@ class PyxImporter(object):
...
@@ -166,18 +179,81 @@ class PyxImporter(object):
for
path
in
filter
(
os
.
path
.
isdir
,
paths
):
for
path
in
filter
(
os
.
path
.
isdir
,
paths
):
for
filename
in
os
.
listdir
(
path
):
for
filename
in
os
.
listdir
(
path
):
if
filename
==
pyx_module_name
:
if
filename
==
pyx_module_name
:
return
PyxLoader
(
fullname
,
join_path
(
path
,
filename
))
return
PyxLoader
(
fullname
,
join_path
(
path
,
filename
),
pyxbuild_dir
=
self
.
pyxbuild_dir
)
elif
filename
==
module_name
:
elif
filename
==
module_name
:
package_path
=
join_path
(
path
,
filename
)
package_path
=
join_path
(
path
,
filename
)
init_path
=
join_path
(
package_path
,
'__init__'
+
PYX_EXT
)
init_path
=
join_path
(
package_path
,
'__init__'
+
self
.
extension
)
if
is_file
(
init_path
):
if
is_file
(
init_path
):
return
PyxLoader
(
fullname
,
package_path
,
init_path
)
return
PyxLoader
(
fullname
,
package_path
,
init_path
,
pyxbuild_dir
=
self
.
pyxbuild_dir
)
# not found, normal package, not a .pyx file, none of our business
# not found, normal package, not a .pyx file, none of our business
return
None
return
None
class
PyImporter
(
PyxImporter
):
"""A meta-path importer for normal .py files.
"""
def
__init__
(
self
,
pyxbuild_dir
=
None
):
self
.
super
=
super
(
PyImporter
,
self
)
self
.
super
.
__init__
(
extension
=
'.py'
,
pyxbuild_dir
=
pyxbuild_dir
)
self
.
uncompilable_modules
=
{}
self
.
blocked_modules
=
[
'Cython'
]
def
find_module
(
self
,
fullname
,
package_path
=
None
):
if
fullname
in
sys
.
modules
:
return
None
if
fullname
.
startswith
(
'Cython.'
):
return
None
if
fullname
in
self
.
blocked_modules
:
# prevent infinite recursion
return
None
if
DEBUG_IMPORT
:
print
"trying import of module %s"
%
fullname
if
fullname
in
self
.
uncompilable_modules
:
path
,
last_modified
=
self
.
uncompilable_modules
[
fullname
]
try
:
new_last_modified
=
os
.
stat
(
path
).
st_mtime
if
new_last_modified
>
last_modified
:
# import would fail again
return
None
except
OSError
:
# module is no longer where we found it, retry the import
pass
self
.
blocked_modules
.
append
(
fullname
)
try
:
importer
=
self
.
super
.
find_module
(
fullname
,
package_path
)
if
importer
is
not
None
:
if
DEBUG_IMPORT
:
print
"importer found"
try
:
if
importer
.
init_path
:
path
=
importer
.
init_path
else
:
path
=
importer
.
path
build_module
(
fullname
,
path
,
pyxbuild_dir
=
self
.
pyxbuild_dir
)
except
Exception
,
e
:
if
DEBUG_IMPORT
:
import
traceback
traceback
.
print_exc
()
# build failed, not a compilable Python module
try
:
last_modified
=
os
.
stat
(
path
).
st_mtime
except
OSError
:
last_modified
=
0
self
.
uncompilable_modules
[
fullname
]
=
(
path
,
last_modified
)
importer
=
None
finally
:
self
.
blocked_modules
.
pop
()
return
importer
class
PyxLoader
(
object
):
class
PyxLoader
(
object
):
def
__init__
(
self
,
fullname
,
path
,
init_path
=
None
):
def
__init__
(
self
,
fullname
,
path
,
init_path
=
None
,
pyxbuild_dir
=
None
):
self
.
fullname
,
self
.
path
,
self
.
init_path
=
fullname
,
path
,
init_path
self
.
fullname
=
fullname
self
.
path
,
self
.
init_path
=
path
,
init_path
self
.
pyxbuild_dir
=
pyxbuild_dir
def
load_module
(
self
,
fullname
):
def
load_module
(
self
,
fullname
):
assert
self
.
fullname
==
fullname
,
(
assert
self
.
fullname
==
fullname
,
(
...
@@ -186,25 +262,50 @@ class PyxLoader(object):
...
@@ -186,25 +262,50 @@ class PyxLoader(object):
if
self
.
init_path
:
if
self
.
init_path
:
# package
# package
#print "PACKAGE", fullname
#print "PACKAGE", fullname
module
=
load_module
(
fullname
,
self
.
init_path
)
module
=
load_module
(
fullname
,
self
.
init_path
,
self
.
pyxbuild_dir
)
module
.
__path__
=
[
self
.
path
]
module
.
__path__
=
[
self
.
path
]
else
:
else
:
#print "MODULE", fullname
#print "MODULE", fullname
module
=
load_module
(
fullname
,
self
.
path
)
module
=
load_module
(
fullname
,
self
.
path
,
self
.
pyxbuild_dir
)
return
module
return
module
def
install
():
def
install
(
pyximport
=
True
,
pyimport
=
False
,
build_dir
=
None
):
"""Main entry point. call this to install the import hook in your
"""Main entry point. Call this to install the .pyx import hook in
for a single Python process. If you want it to be installed whenever
your meta-path for a single Python process. If you want it to be
you use Python, add it to your sitecustomize (as described above).
installed whenever you use Python, add it to your sitecustomize
(as described above).
You can pass ``pyimport=True`` to also install the .py import hook
in your meta-path. Note, however, that it is highly experimental,
will not work for most .py files, and will therefore only slow
down your imports. Use at your own risk.
By default, compiled modules will end up in a ``.pyxbld``
directory in the user's home directory. Passing a different path
as ``build_dir`` will override this.
"""
"""
if
not
build_dir
:
build_dir
=
os
.
path
.
expanduser
(
'~/.pyxbld'
)
has_py_importer
=
False
has_pyx_importer
=
False
for
importer
in
sys
.
meta_path
:
for
importer
in
sys
.
meta_path
:
if
isinstance
(
importer
,
PyxImporter
):
if
isinstance
(
importer
,
PyxImporter
):
return
if
isinstance
(
importer
,
PyImporter
):
importer
=
PyxImporter
()
# ('~/.pyxbuild')
has_py_importer
=
True
sys
.
meta_path
.
append
(
importer
)
else
:
has_pyx_importer
=
True
if
pyimport
and
not
has_py_importer
:
importer
=
PyImporter
(
pyxbuild_dir
=
build_dir
)
sys
.
meta_path
.
insert
(
0
,
importer
)
if
pyximport
and
not
has_pyx_importer
:
importer
=
PyxImporter
(
pyxbuild_dir
=
build_dir
)
sys
.
meta_path
.
append
(
importer
)
# MAIN
# MAIN
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment