[pypy-commit] cffi default: Test and various fixes for the location of the produced files, notably
arigo
noreply at buildbot.pypy.org
Wed May 27 11:36:31 CEST 2015
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r2109:01e7a78ca0ff
Date: 2015-05-27 11:37 +0200
http://bitbucket.org/cffi/cffi/changeset/01e7a78ca0ff/
Log: Test and various fixes for the location of the produced files,
notably during the calls to ffi.compile()
diff --git a/cffi/recompiler.py b/cffi/recompiler.py
--- a/cffi/recompiler.py
+++ b/cffi/recompiler.py
@@ -1159,9 +1159,14 @@
def make_py_source(ffi, module_name, target_py_file):
return _make_c_or_py_source(ffi, module_name, None, target_py_file)
-def _get_extension(module_name, c_file, kwds):
- source_name = ffiplatform.maybe_relative_path(c_file)
- return ffiplatform.get_extension(source_name, module_name, **kwds)
+def _modname_to_file(outputdir, modname, extension):
+ parts = modname.split('.')
+ try:
+ os.makedirs(os.path.join(outputdir, *parts[:-1]))
+ except OSError:
+ pass
+ parts[-1] += extension
+ return os.path.join(outputdir, *parts), parts
def recompile(ffi, module_name, preamble, tmpdir='.', call_c_compiler=True,
c_file=None, source_extension='.c', **kwds):
@@ -1171,17 +1176,26 @@
ffi._apply_windows_unicode(kwds)
if preamble is not None:
if c_file is None:
- c_file = os.path.join(tmpdir, module_name + source_extension)
- ext = _get_extension(module_name, c_file, kwds)
+ c_file, parts = _modname_to_file(tmpdir, module_name,
+ source_extension)
+ ext_c_file = os.path.join(*parts)
+ else:
+ ext_c_file = c_file
+ ext = ffiplatform.get_extension(ext_c_file, module_name, **kwds)
updated = make_c_source(ffi, module_name, preamble, c_file)
if call_c_compiler:
- outputfilename = ffiplatform.compile(tmpdir, ext)
+ cwd = os.getcwd()
+ try:
+ os.chdir(tmpdir)
+ outputfilename = ffiplatform.compile('.', ext)
+ finally:
+ os.chdir(cwd)
return outputfilename
else:
return ext, updated
else:
if c_file is None:
- c_file = os.path.join(tmpdir, module_name + '.py')
+ c_file, _ = _modname_to_file(tmpdir, module_name, '.py')
updated = make_py_source(ffi, module_name, c_file)
if call_c_compiler:
return c_file
diff --git a/doc/source/cdef.rst b/doc/source/cdef.rst
--- a/doc/source/cdef.rst
+++ b/doc/source/cdef.rst
@@ -442,7 +442,9 @@
directory given by ``tmpdir``. In the examples given here, we use
``if __name__ == "__main__": ffi.compile()`` in the build scripts---if
they are directly executed, this makes them rebuild the .py/.c file in
-the current directory.
+the current directory. (Note: if a package is specified in the call
+to ``set_source()``, then a corresponding subdirectory of the ``tmpdir``
+is used.)
**ffi.emit_python_code(filename):** generate the given .py file (same
as ``ffi.compile()`` for ABI mode, with an explicitly-named file to
diff --git a/doc/source/whatsnew.rst b/doc/source/whatsnew.rst
--- a/doc/source/whatsnew.rst
+++ b/doc/source/whatsnew.rst
@@ -6,6 +6,10 @@
1.0.4
=====
+* Issue #196: ``ffi.set_source("package._ffi", None)`` would
+ incorrectly generate the Python source to ``package._ffi.py``
+ instead of ``package/_ffi.py``.
+
* ffi.addressof(lib, "func_name") now returns a regular cdata object
of type "pointer to function". You can use it on any function from a
library in API mode (in ABI mode, all functions are already regular
diff --git a/testing/cffi1/test_recompiler.py b/testing/cffi1/test_recompiler.py
--- a/testing/cffi1/test_recompiler.py
+++ b/testing/cffi1/test_recompiler.py
@@ -478,8 +478,11 @@
old_sys_path = sys.path[:]
try:
package_dir = udir.join('test_module_name_in_package')
+ for name in os.listdir(str(udir)):
+ assert not name.startswith('test_module_name_in_package.')
assert os.path.isdir(str(package_dir))
assert len(os.listdir(str(package_dir))) > 0
+ assert os.path.exists(str(package_dir.join('mymod.c')))
package_dir.join('__init__.py').write('')
#
sys.path.insert(0, str(udir))
diff --git a/testing/cffi1/test_zdist.py b/testing/cffi1/test_zdist.py
new file mode 100644
--- /dev/null
+++ b/testing/cffi1/test_zdist.py
@@ -0,0 +1,153 @@
+import os, py
+import cffi
+from testing.udir import udir
+
+
+def chdir_to_tmp(f):
+ f.chdir_to_tmp = True
+ return f
+
+def from_outside(f):
+ f.chdir_to_tmp = False
+ return f
+
+
+class TestDist(object):
+
+ def setup_method(self, meth):
+ self.udir = udir.join(meth.__name__)
+ os.mkdir(str(self.udir))
+ if meth.chdir_to_tmp:
+ self.saved_cwd = os.getcwd()
+ os.chdir(str(self.udir))
+
+ def teardown_method(self, meth):
+ if hasattr(self, 'saved_cwd'):
+ os.chdir(self.saved_cwd)
+
+ def check_produced_files(self, content, curdir=None):
+ if curdir is None:
+ curdir = str(self.udir)
+ found_so = None
+ for name in os.listdir(curdir):
+ if (name.endswith('.so') or name.endswith('.pyd') or
+ name.endswith('.dylib')):
+ found_so = os.path.join(curdir, name)
+ name = os.path.splitext(name)[0] + '.SO'
+ assert name in content, "found unexpected file %r" % (
+ os.path.join(curdir, name),)
+ value = content.pop(name)
+ if value is None:
+ assert name.endswith('.SO') or (
+ os.path.isfile(os.path.join(curdir, name)))
+ else:
+ subdir = os.path.join(curdir, name)
+ assert os.path.isdir(subdir)
+ found_so = self.check_produced_files(value, subdir) or found_so
+ assert content == {}, "files or dirs not produced in %r: %r" % (
+ curdir, content.keys())
+ return found_so
+
+ @chdir_to_tmp
+ def test_empty(self):
+ self.check_produced_files({})
+
+ @chdir_to_tmp
+ def test_abi_emit_python_code_1(self):
+ ffi = cffi.FFI()
+ ffi.set_source("package_name_1.mymod", None)
+ ffi.emit_python_code('xyz.py')
+ self.check_produced_files({'xyz.py': None})
+
+ @chdir_to_tmp
+ def test_abi_emit_python_code_2(self):
+ ffi = cffi.FFI()
+ ffi.set_source("package_name_1.mymod", None)
+ py.test.raises(IOError, ffi.emit_python_code, 'unexisting/xyz.py')
+
+ @from_outside
+ def test_abi_emit_python_code_3(self):
+ ffi = cffi.FFI()
+ ffi.set_source("package_name_1.mymod", None)
+ ffi.emit_python_code(str(self.udir.join('xyt.py')))
+ self.check_produced_files({'xyt.py': None})
+
+ @chdir_to_tmp
+ def test_abi_compile_1(self):
+ ffi = cffi.FFI()
+ ffi.set_source("mod_name_in_package.mymod", None)
+ x = ffi.compile()
+ self.check_produced_files({'mod_name_in_package': {'mymod.py': None}})
+ assert x == os.path.join('.', 'mod_name_in_package', 'mymod.py')
+
+ @chdir_to_tmp
+ def test_abi_compile_2(self):
+ ffi = cffi.FFI()
+ ffi.set_source("mod_name_in_package.mymod", None)
+ x = ffi.compile('build2')
+ self.check_produced_files({'build2': {
+ 'mod_name_in_package': {'mymod.py': None}}})
+ assert x == os.path.join('build2', 'mod_name_in_package', 'mymod.py')
+
+ @from_outside
+ def test_abi_compile_3(self):
+ ffi = cffi.FFI()
+ ffi.set_source("mod_name_in_package.mymod", None)
+ tmpdir = str(self.udir.join('build3'))
+ x = ffi.compile(tmpdir)
+ self.check_produced_files({'build3': {
+ 'mod_name_in_package': {'mymod.py': None}}})
+ assert x == os.path.join(tmpdir, 'mod_name_in_package', 'mymod.py')
+
+ @chdir_to_tmp
+ def test_api_emit_c_code_1(self):
+ ffi = cffi.FFI()
+ ffi.set_source("package_name_1.mymod", "/*code would be here*/")
+ ffi.emit_c_code('xyz.c')
+ self.check_produced_files({'xyz.c': None})
+
+ @chdir_to_tmp
+ def test_api_emit_c_code_2(self):
+ ffi = cffi.FFI()
+ ffi.set_source("package_name_1.mymod", "/*code would be here*/")
+ py.test.raises(IOError, ffi.emit_c_code, 'unexisting/xyz.c')
+
+ @from_outside
+ def test_api_emit_c_code_3(self):
+ ffi = cffi.FFI()
+ ffi.set_source("package_name_1.mymod", "/*code would be here*/")
+ ffi.emit_c_code(str(self.udir.join('xyu.c')))
+ self.check_produced_files({'xyu.c': None})
+
+ @chdir_to_tmp
+ def test_api_compile_1(self):
+ ffi = cffi.FFI()
+ ffi.set_source("mod_name_in_package.mymod", "/*code would be here*/")
+ x = ffi.compile()
+ sofile = self.check_produced_files({
+ 'mod_name_in_package': {'mymod.SO': None,
+ 'mymod.c': None,
+ 'mymod.o': None}})
+ assert os.path.isabs(x) and os.path.samefile(x, sofile)
+
+ @chdir_to_tmp
+ def test_api_compile_2(self):
+ ffi = cffi.FFI()
+ ffi.set_source("mod_name_in_package.mymod", "/*code would be here*/")
+ x = ffi.compile('output')
+ sofile = self.check_produced_files({
+ 'output': {'mod_name_in_package': {'mymod.SO': None,
+ 'mymod.c': None,
+ 'mymod.o': None}}})
+ assert os.path.isabs(x) and os.path.samefile(x, sofile)
+
+ @from_outside
+ def test_api_compile_3(self):
+ ffi = cffi.FFI()
+ ffi.set_source("mod_name_in_package.mymod", "/*code would be here*/")
+ x = ffi.compile(str(self.udir.join('foo')))
+ sofile = self.check_produced_files({
+ 'foo': {'mod_name_in_package': {'mymod.SO': None,
+ 'mymod.c': None,
+ 'mymod.o': None}}})
+ assert os.path.isabs(x) and os.path.samefile(x, sofile)
More information about the pypy-commit
mailing list