test_venv.py 7.54 KB
Newer Older
1 2
"""
Test harness for the venv module.
3

4
Copyright (C) 2011-2012 Vinay Sajip.
5
Licensed to the PSF under a contributor agreement.
6 7 8 9 10
"""

import os
import os.path
import shutil
11
import subprocess
12 13 14 15 16 17 18 19 20 21 22
import sys
import tempfile
from test.support import (captured_stdout, captured_stderr, run_unittest,
                          can_symlink)
import unittest
import venv

class BaseTest(unittest.TestCase):
    """Base class for venv tests."""

    def setUp(self):
23
        self.env_dir = os.path.realpath(tempfile.mkdtemp())
24 25
        if os.name == 'nt':
            self.bindir = 'Scripts'
26
            self.pydocname = 'pydoc.py'
27 28 29 30
            self.lib = ('Lib',)
            self.include = 'Include'
        else:
            self.bindir = 'bin'
31
            self.pydocname = 'pydoc'
32 33
            self.lib = ('lib', 'python%s' % sys.version[:3])
            self.include = 'include'
34 35
        if sys.platform == 'darwin' and '__PYVENV_LAUNCHER__' in os.environ:
            executable = os.environ['__PYVENV_LAUNCHER__']
36 37 38
        else:
            executable = sys.executable
        self.exe = os.path.split(executable)[-1]
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59

    def tearDown(self):
        shutil.rmtree(self.env_dir)

    def run_with_capture(self, func, *args, **kwargs):
        with captured_stdout() as output:
            with captured_stderr() as error:
                func(*args, **kwargs)
        return output.getvalue(), error.getvalue()

    def get_env_file(self, *args):
        return os.path.join(self.env_dir, *args)

    def get_text_file_contents(self, *args):
        with open(self.get_env_file(*args), 'r') as f:
            result = f.read()
        return result

class BasicTest(BaseTest):
    """Test venv module functionality."""

Vinay Sajip's avatar
Vinay Sajip committed
60 61 62 63
    def isdir(self, *args):
        fn = self.get_env_file(*args)
        self.assertTrue(os.path.isdir(fn))

64 65 66 67 68 69
    def test_defaults(self):
        """
        Test the create function with default arguments.
        """
        shutil.rmtree(self.env_dir)
        self.run_with_capture(venv.create, self.env_dir)
Vinay Sajip's avatar
Vinay Sajip committed
70 71 72
        self.isdir(self.bindir)
        self.isdir(self.include)
        self.isdir(*self.lib)
73
        data = self.get_text_file_contents('pyvenv.cfg')
74
        if sys.platform == 'darwin' and ('__PYVENV_LAUNCHER__'
75
                                         in os.environ):
76
            executable =  os.environ['__PYVENV_LAUNCHER__']
77 78 79 80
        else:
            executable = sys.executable
        path = os.path.dirname(executable)
        self.assertIn('home = %s' % path, data)
81 82
        data = self.get_text_file_contents(self.bindir, self.pydocname)
        self.assertTrue(data.startswith('#!%s%s' % (self.env_dir, os.sep)))
83
        fn = self.get_env_file(self.bindir, self.exe)
84
        if not os.path.exists(fn):  # diagnostics for Windows buildbot failures
Vinay Sajip's avatar
Vinay Sajip committed
85 86 87
            bd = self.get_env_file(self.bindir)
            print('Contents of %r:' % bd)
            print('    %r' % os.listdir(bd))
88
        self.assertTrue(os.path.exists(fn), 'File %r should exist.' % fn)
89

90 91
    @unittest.skipIf(sys.prefix != sys.base_prefix, 'Test not appropriate '
                     'in a venv')
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
    def test_prefixes(self):
        """
        Test that the prefix values are as expected.
        """
        #check our prefixes
        self.assertEqual(sys.base_prefix, sys.prefix)
        self.assertEqual(sys.base_exec_prefix, sys.exec_prefix)

        # check a venv's prefixes
        shutil.rmtree(self.env_dir)
        self.run_with_capture(venv.create, self.env_dir)
        envpy = os.path.join(self.env_dir, self.bindir, self.exe)
        cmd = [envpy, '-c', None]
        for prefix, expected in (
            ('prefix', self.env_dir),
            ('prefix', self.env_dir),
            ('base_prefix', sys.prefix),
            ('base_exec_prefix', sys.exec_prefix)):
            cmd[2] = 'import sys; print(sys.%s)' % prefix
            p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE)
            out, err = p.communicate()
114
            self.assertEqual(out.strip(), expected.encode())
115

116 117 118 119 120 121 122 123
    def test_overwrite_existing(self):
        """
        Test control of overwriting an existing environment directory.
        """
        self.assertRaises(ValueError, venv.create, self.env_dir)
        builder = venv.EnvBuilder(clear=True)
        builder.create(self.env_dir)

Vinay Sajip's avatar
Vinay Sajip committed
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
    def test_upgrade(self):
        """
        Test upgrading an existing environment directory.
        """
        builder = venv.EnvBuilder(upgrade=True)
        self.run_with_capture(builder.create, self.env_dir)
        self.isdir(self.bindir)
        self.isdir(self.include)
        self.isdir(*self.lib)
        fn = self.get_env_file(self.bindir, self.exe)
        if not os.path.exists(fn):  # diagnostics for Windows buildbot failures
            bd = self.get_env_file(self.bindir)
            print('Contents of %r:' % bd)
            print('    %r' % os.listdir(bd))
        self.assertTrue(os.path.exists(fn), 'File %r should exist.' % fn)

140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
    def test_isolation(self):
        """
        Test isolation from system site-packages
        """
        for ssp, s in ((True, 'true'), (False, 'false')):
            builder = venv.EnvBuilder(clear=True, system_site_packages=ssp)
            builder.create(self.env_dir)
            data = self.get_text_file_contents('pyvenv.cfg')
            self.assertIn('include-system-site-packages = %s\n' % s, data)

    @unittest.skipUnless(can_symlink(), 'Needs symlinks')
    def test_symlinking(self):
        """
        Test symlinking works as expected
        """
        for usl in (False, True):
            builder = venv.EnvBuilder(clear=True, symlinks=usl)
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
            builder.create(self.env_dir)
            fn = self.get_env_file(self.bindir, self.exe)
            # Don't test when False, because e.g. 'python' is always
            # symlinked to 'python3.3' in the env, even when symlinking in
            # general isn't wanted.
            if usl:
                self.assertTrue(os.path.islink(fn))

    # If a venv is created from a source build and that venv is used to
    # run the test, the pyvenv.cfg in the venv created in the test will
    # point to the venv being used to run the test, and we lose the link
    # to the source build - so Python can't initialise properly.
    @unittest.skipIf(sys.prefix != sys.base_prefix, 'Test not appropriate '
                     'in a venv')
    def test_executable(self):
        """
        Test that the sys.executable value is as expected.
        """
        shutil.rmtree(self.env_dir)
        self.run_with_capture(venv.create, self.env_dir)
        envpy = os.path.join(os.path.realpath(self.env_dir), self.bindir, self.exe)
        cmd = [envpy, '-c', 'import sys; print(sys.executable)']
        p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE)
        out, err = p.communicate()
182
        self.assertEqual(out.strip(), envpy.encode())
183 184 185 186 187 188 189 190 191 192 193 194 195 196

    @unittest.skipUnless(can_symlink(), 'Needs symlinks')
    def test_executable_symlinks(self):
        """
        Test that the sys.executable value is as expected.
        """
        shutil.rmtree(self.env_dir)
        builder = venv.EnvBuilder(clear=True, symlinks=True)
        builder.create(self.env_dir)
        envpy = os.path.join(os.path.realpath(self.env_dir), self.bindir, self.exe)
        cmd = [envpy, '-c', 'import sys; print(sys.executable)']
        p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE)
        out, err = p.communicate()
197
        self.assertEqual(out.strip(), envpy.encode())
198 199 200 201 202 203

def test_main():
    run_unittest(BasicTest)

if __name__ == "__main__":
    test_main()