• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import py, os, sys, shutil
2import subprocess
3from testing.udir import udir
4import pytest
5
6if sys.platform == 'win32':
7    pytestmark = pytest.mark.skip('snippets do not run on win32')
8if sys.version_info < (2, 7):
9    pytestmark = pytest.mark.skip(
10                 'fails e.g. on a Debian/Ubuntu which patches virtualenv'
11                 ' in a non-2.6-friendly way')
12
13def create_venv(name):
14    tmpdir = udir.join(name)
15    try:
16        subprocess.check_call(['virtualenv',
17            #'--never-download', <= could be added, but causes failures
18            # in random cases on random machines
19                               '-p', os.path.abspath(sys.executable),
20                               str(tmpdir)])
21    except OSError as e:
22        py.test.skip("Cannot execute virtualenv: %s" % (e,))
23
24    site_packages = None
25    for dirpath, dirnames, filenames in os.walk(str(tmpdir)):
26        if os.path.basename(dirpath) == 'site-packages':
27            site_packages = dirpath
28            break
29    paths = ""
30    if site_packages:
31        try:
32            from cffi import _pycparser
33            modules = ('cffi', '_cffi_backend')
34        except ImportError:
35            modules = ('cffi', '_cffi_backend', 'pycparser')
36            try:
37                import ply
38            except ImportError:
39                pass
40            else:
41                modules += ('ply',)   # needed for older versions of pycparser
42        paths = []
43        for module in modules:
44            target = __import__(module, None, None, [])
45            if not hasattr(target, '__file__'):   # for _cffi_backend on pypy
46                continue
47            src = os.path.abspath(target.__file__)
48            for end in ['__init__.pyc', '__init__.pyo', '__init__.py']:
49                if src.lower().endswith(end):
50                    src = src[:-len(end)-1]
51                    break
52            paths.append(os.path.dirname(src))
53        paths = os.pathsep.join(paths)
54    return tmpdir, paths
55
56SNIPPET_DIR = py.path.local(__file__).join('..', 'snippets')
57
58def really_run_setup_and_program(dirname, venv_dir_and_paths, python_snippet):
59    venv_dir, paths = venv_dir_and_paths
60    def remove(dir):
61        dir = str(SNIPPET_DIR.join(dirname, dir))
62        shutil.rmtree(dir, ignore_errors=True)
63    remove('build')
64    remove('__pycache__')
65    for basedir in os.listdir(str(SNIPPET_DIR.join(dirname))):
66        remove(os.path.join(basedir, '__pycache__'))
67    olddir = os.getcwd()
68    python_f = udir.join('x.py')
69    python_f.write(py.code.Source(python_snippet))
70    try:
71        os.chdir(str(SNIPPET_DIR.join(dirname)))
72        if os.name == 'nt':
73            bindir = 'Scripts'
74        else:
75            bindir = 'bin'
76        vp = str(venv_dir.join(bindir).join('python'))
77        env = os.environ.copy()
78        env['PYTHONPATH'] = paths
79        subprocess.check_call((vp, 'setup.py', 'clean'), env=env)
80        # there's a setuptools/easy_install bug that causes this to fail when the build/install occur together and
81        # we're in the same directory with the build (it tries to look up dependencies for itself on PyPI);
82        # subsequent runs will succeed because this test doesn't properly clean up the build- use pip for now.
83        subprocess.check_call((vp, '-m', 'pip', 'install', '.'), env=env)
84        subprocess.check_call((vp, str(python_f)), env=env)
85    finally:
86        os.chdir(olddir)
87
88def run_setup_and_program(dirname, python_snippet):
89    venv_dir = create_venv(dirname + '-cpy')
90    really_run_setup_and_program(dirname, venv_dir, python_snippet)
91    #
92    sys._force_generic_engine_ = True
93    try:
94        venv_dir = create_venv(dirname + '-gen')
95        really_run_setup_and_program(dirname, venv_dir, python_snippet)
96    finally:
97        del sys._force_generic_engine_
98    # the two files lextab.py and yacctab.py are created by not-correctly-
99    # installed versions of pycparser.
100    assert not os.path.exists(str(SNIPPET_DIR.join(dirname, 'lextab.py')))
101    assert not os.path.exists(str(SNIPPET_DIR.join(dirname, 'yacctab.py')))
102
103class TestZIntegration(object):
104    def teardown_class(self):
105        if udir.isdir():
106            udir.remove(ignore_errors=True)
107        udir.ensure(dir=1)
108
109    def test_infrastructure(self):
110        run_setup_and_program('infrastructure', '''
111        import snip_infrastructure
112        assert snip_infrastructure.func() == 42
113        ''')
114
115    def test_distutils_module(self):
116        run_setup_and_program("distutils_module", '''
117        import snip_basic_verify
118        p = snip_basic_verify.C.getpwuid(0)
119        assert snip_basic_verify.ffi.string(p.pw_name) == b"root"
120        ''')
121
122    def test_distutils_package_1(self):
123        run_setup_and_program("distutils_package_1", '''
124        import snip_basic_verify1
125        p = snip_basic_verify1.C.getpwuid(0)
126        assert snip_basic_verify1.ffi.string(p.pw_name) == b"root"
127        ''')
128
129    def test_distutils_package_2(self):
130        run_setup_and_program("distutils_package_2", '''
131        import snip_basic_verify2
132        p = snip_basic_verify2.C.getpwuid(0)
133        assert snip_basic_verify2.ffi.string(p.pw_name) == b"root"
134        ''')
135
136    def test_setuptools_module(self):
137        run_setup_and_program("setuptools_module", '''
138        import snip_setuptools_verify
139        p = snip_setuptools_verify.C.getpwuid(0)
140        assert snip_setuptools_verify.ffi.string(p.pw_name) == b"root"
141        ''')
142
143    def test_setuptools_package_1(self):
144        run_setup_and_program("setuptools_package_1", '''
145        import snip_setuptools_verify1
146        p = snip_setuptools_verify1.C.getpwuid(0)
147        assert snip_setuptools_verify1.ffi.string(p.pw_name) == b"root"
148        ''')
149
150    def test_setuptools_package_2(self):
151        run_setup_and_program("setuptools_package_2", '''
152        import snip_setuptools_verify2
153        p = snip_setuptools_verify2.C.getpwuid(0)
154        assert snip_setuptools_verify2.ffi.string(p.pw_name) == b"root"
155        ''')
156
157    def test_set_py_limited_api(self):
158        from cffi.setuptools_ext import _set_py_limited_api
159        try:
160            import setuptools
161        except ImportError as e:
162            py.test.skip(str(e))
163        orig_version = setuptools.__version__
164        expecting_limited_api = not hasattr(sys, 'gettotalrefcount')
165        try:
166            setuptools.__version__ = '26.0.0'
167            from setuptools import Extension
168
169            kwds = _set_py_limited_api(Extension, {})
170            assert kwds.get('py_limited_api', False) == expecting_limited_api
171
172            setuptools.__version__ = '25.0'
173            kwds = _set_py_limited_api(Extension, {})
174            assert kwds.get('py_limited_api', False) == False
175
176            setuptools.__version__ = 'development'
177            kwds = _set_py_limited_api(Extension, {})
178            assert kwds.get('py_limited_api', False) == expecting_limited_api
179
180        finally:
181            setuptools.__version__ = orig_version
182