blob: 2a528c92bd0bbc764a1a9f17b1b0b8fe27de555d [file] [log] [blame]
Vinay Sajip42211422012-05-26 20:36:12 +01001"""
2Test harness for the venv module.
Vinay Sajip7ded1f02012-05-26 03:45:29 +01003
Vinay Sajip42211422012-05-26 20:36:12 +01004Copyright (C) 2011-2012 Vinay Sajip.
Vinay Sajip28952442012-06-25 00:47:46 +01005Licensed to the PSF under a contributor agreement.
Vinay Sajip7ded1f02012-05-26 03:45:29 +01006"""
7
8import os
9import os.path
10import shutil
Vinay Sajip3874e542012-07-03 16:56:40 +010011import subprocess
Vinay Sajip7ded1f02012-05-26 03:45:29 +010012import sys
13import tempfile
14from test.support import (captured_stdout, captured_stderr, run_unittest,
15 can_symlink)
16import unittest
17import venv
18
19class BaseTest(unittest.TestCase):
20 """Base class for venv tests."""
21
22 def setUp(self):
Ned Deily045bd532012-07-13 15:48:04 -070023 self.env_dir = os.path.realpath(tempfile.mkdtemp())
Vinay Sajip7ded1f02012-05-26 03:45:29 +010024 if os.name == 'nt':
25 self.bindir = 'Scripts'
Éric Araujoaa789ac2012-06-24 13:51:22 -040026 self.pydocname = 'pydoc.py'
Vinay Sajip7ded1f02012-05-26 03:45:29 +010027 self.lib = ('Lib',)
28 self.include = 'Include'
Vinay Sajip7ded1f02012-05-26 03:45:29 +010029 else:
30 self.bindir = 'bin'
Éric Araujoaa789ac2012-06-24 13:51:22 -040031 self.pydocname = 'pydoc'
Vinay Sajip7ded1f02012-05-26 03:45:29 +010032 self.lib = ('lib', 'python%s' % sys.version[:3])
33 self.include = 'include'
Vinay Sajip28952442012-06-25 00:47:46 +010034 if sys.platform == 'darwin' and '__PYVENV_LAUNCHER__' in os.environ:
35 executable = os.environ['__PYVENV_LAUNCHER__']
Vinay Sajip382a7c02012-05-28 16:34:47 +010036 else:
37 executable = sys.executable
38 self.exe = os.path.split(executable)[-1]
Vinay Sajip7ded1f02012-05-26 03:45:29 +010039
40 def tearDown(self):
41 shutil.rmtree(self.env_dir)
42
43 def run_with_capture(self, func, *args, **kwargs):
44 with captured_stdout() as output:
45 with captured_stderr() as error:
46 func(*args, **kwargs)
47 return output.getvalue(), error.getvalue()
48
49 def get_env_file(self, *args):
50 return os.path.join(self.env_dir, *args)
51
52 def get_text_file_contents(self, *args):
53 with open(self.get_env_file(*args), 'r') as f:
54 result = f.read()
55 return result
56
57class BasicTest(BaseTest):
58 """Test venv module functionality."""
59
Vinay Sajipb3b49cd2012-05-27 18:39:22 +010060 def isdir(self, *args):
61 fn = self.get_env_file(*args)
62 self.assertTrue(os.path.isdir(fn))
63
Vinay Sajip7ded1f02012-05-26 03:45:29 +010064 def test_defaults(self):
65 """
66 Test the create function with default arguments.
67 """
Vinay Sajip7ded1f02012-05-26 03:45:29 +010068 shutil.rmtree(self.env_dir)
69 self.run_with_capture(venv.create, self.env_dir)
Vinay Sajipb3b49cd2012-05-27 18:39:22 +010070 self.isdir(self.bindir)
71 self.isdir(self.include)
72 self.isdir(*self.lib)
Vinay Sajip7ded1f02012-05-26 03:45:29 +010073 data = self.get_text_file_contents('pyvenv.cfg')
Vinay Sajip28952442012-06-25 00:47:46 +010074 if sys.platform == 'darwin' and ('__PYVENV_LAUNCHER__'
Vinay Sajip7ded1f02012-05-26 03:45:29 +010075 in os.environ):
Vinay Sajip28952442012-06-25 00:47:46 +010076 executable = os.environ['__PYVENV_LAUNCHER__']
Vinay Sajip7ded1f02012-05-26 03:45:29 +010077 else:
78 executable = sys.executable
79 path = os.path.dirname(executable)
80 self.assertIn('home = %s' % path, data)
Éric Araujoaa789ac2012-06-24 13:51:22 -040081 data = self.get_text_file_contents(self.bindir, self.pydocname)
82 self.assertTrue(data.startswith('#!%s%s' % (self.env_dir, os.sep)))
Vinay Sajip7ded1f02012-05-26 03:45:29 +010083 fn = self.get_env_file(self.bindir, self.exe)
Vinay Sajip7e203492012-05-27 17:30:09 +010084 if not os.path.exists(fn): # diagnostics for Windows buildbot failures
Vinay Sajipb3b49cd2012-05-27 18:39:22 +010085 bd = self.get_env_file(self.bindir)
86 print('Contents of %r:' % bd)
87 print(' %r' % os.listdir(bd))
Vinay Sajip7e203492012-05-27 17:30:09 +010088 self.assertTrue(os.path.exists(fn), 'File %r should exist.' % fn)
Vinay Sajip7ded1f02012-05-26 03:45:29 +010089
Vinay Sajip509d87d2012-07-15 16:12:54 +010090 @unittest.skipIf(sys.prefix != sys.base_prefix, 'Test not appropriate '
91 'in a venv')
Vinay Sajip3874e542012-07-03 16:56:40 +010092 def test_prefixes(self):
93 """
94 Test that the prefix values are as expected.
95 """
96 #check our prefixes
97 self.assertEqual(sys.base_prefix, sys.prefix)
98 self.assertEqual(sys.base_exec_prefix, sys.exec_prefix)
99
100 # check a venv's prefixes
101 shutil.rmtree(self.env_dir)
102 self.run_with_capture(venv.create, self.env_dir)
103 envpy = os.path.join(self.env_dir, self.bindir, self.exe)
104 cmd = [envpy, '-c', None]
105 for prefix, expected in (
106 ('prefix', self.env_dir),
107 ('prefix', self.env_dir),
108 ('base_prefix', sys.prefix),
109 ('base_exec_prefix', sys.exec_prefix)):
110 cmd[2] = 'import sys; print(sys.%s)' % prefix
111 p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
112 stderr=subprocess.PIPE)
113 out, err = p.communicate()
Antoine Pitrou9c92a692012-08-05 00:33:10 +0200114 self.assertEqual(out.strip(), expected.encode())
Vinay Sajip3874e542012-07-03 16:56:40 +0100115
Vinay Sajipbd40d3e2012-10-11 17:22:45 +0100116 if sys.platform == 'win32':
117 ENV_SUBDIRS = (
118 ('Scripts',),
119 ('Include',),
120 ('Lib',),
121 ('Lib', 'site-packages'),
122 )
123 else:
124 ENV_SUBDIRS = (
125 ('bin',),
126 ('include',),
127 ('lib',),
128 ('lib', 'python%d.%d' % sys.version_info[:2]),
129 ('lib', 'python%d.%d' % sys.version_info[:2], 'site-packages'),
130 )
131
132 def create_contents(self, paths, filename):
133 """
134 Create some files in the environment which are unrelated
135 to the virtual environment.
136 """
137 for subdirs in paths:
138 d = os.path.join(self.env_dir, *subdirs)
139 os.mkdir(d)
140 fn = os.path.join(d, filename)
141 with open(fn, 'wb') as f:
142 f.write(b'Still here?')
143
Vinay Sajip7ded1f02012-05-26 03:45:29 +0100144 def test_overwrite_existing(self):
145 """
Vinay Sajipbd40d3e2012-10-11 17:22:45 +0100146 Test creating environment in an existing directory.
Vinay Sajip7ded1f02012-05-26 03:45:29 +0100147 """
Vinay Sajipbd40d3e2012-10-11 17:22:45 +0100148 self.create_contents(self.ENV_SUBDIRS, 'foo')
149 venv.create(self.env_dir)
150 for subdirs in self.ENV_SUBDIRS:
151 fn = os.path.join(self.env_dir, *(subdirs + ('foo',)))
152 self.assertTrue(os.path.exists(fn))
153 with open(fn, 'rb') as f:
154 self.assertEqual(f.read(), b'Still here?')
155
Vinay Sajip7ded1f02012-05-26 03:45:29 +0100156 builder = venv.EnvBuilder(clear=True)
157 builder.create(self.env_dir)
Vinay Sajipbd40d3e2012-10-11 17:22:45 +0100158 for subdirs in self.ENV_SUBDIRS:
159 fn = os.path.join(self.env_dir, *(subdirs + ('foo',)))
160 self.assertFalse(os.path.exists(fn))
161
162 def clear_directory(self, path):
163 for fn in os.listdir(path):
164 fn = os.path.join(path, fn)
165 if os.path.islink(fn) or os.path.isfile(fn):
166 os.remove(fn)
167 elif os.path.isdir(fn):
168 shutil.rmtree(fn)
169
170 def test_unoverwritable_fails(self):
171 #create a file clashing with directories in the env dir
172 for paths in self.ENV_SUBDIRS[:3]:
173 fn = os.path.join(self.env_dir, *paths)
174 with open(fn, 'wb') as f:
175 f.write(b'')
176 self.assertRaises((ValueError, OSError), venv.create, self.env_dir)
177 self.clear_directory(self.env_dir)
Vinay Sajip7ded1f02012-05-26 03:45:29 +0100178
Vinay Sajipb3b49cd2012-05-27 18:39:22 +0100179 def test_upgrade(self):
180 """
181 Test upgrading an existing environment directory.
182 """
183 builder = venv.EnvBuilder(upgrade=True)
184 self.run_with_capture(builder.create, self.env_dir)
185 self.isdir(self.bindir)
186 self.isdir(self.include)
187 self.isdir(*self.lib)
188 fn = self.get_env_file(self.bindir, self.exe)
189 if not os.path.exists(fn): # diagnostics for Windows buildbot failures
190 bd = self.get_env_file(self.bindir)
191 print('Contents of %r:' % bd)
192 print(' %r' % os.listdir(bd))
193 self.assertTrue(os.path.exists(fn), 'File %r should exist.' % fn)
194
Vinay Sajip7ded1f02012-05-26 03:45:29 +0100195 def test_isolation(self):
196 """
197 Test isolation from system site-packages
198 """
199 for ssp, s in ((True, 'true'), (False, 'false')):
200 builder = venv.EnvBuilder(clear=True, system_site_packages=ssp)
201 builder.create(self.env_dir)
202 data = self.get_text_file_contents('pyvenv.cfg')
203 self.assertIn('include-system-site-packages = %s\n' % s, data)
204
205 @unittest.skipUnless(can_symlink(), 'Needs symlinks')
206 def test_symlinking(self):
207 """
208 Test symlinking works as expected
209 """
210 for usl in (False, True):
211 builder = venv.EnvBuilder(clear=True, symlinks=usl)
Vinay Sajip90db6612012-07-17 17:33:46 +0100212 builder.create(self.env_dir)
213 fn = self.get_env_file(self.bindir, self.exe)
214 # Don't test when False, because e.g. 'python' is always
215 # symlinked to 'python3.3' in the env, even when symlinking in
216 # general isn't wanted.
217 if usl:
218 self.assertTrue(os.path.islink(fn))
219
220 # If a venv is created from a source build and that venv is used to
221 # run the test, the pyvenv.cfg in the venv created in the test will
222 # point to the venv being used to run the test, and we lose the link
223 # to the source build - so Python can't initialise properly.
224 @unittest.skipIf(sys.prefix != sys.base_prefix, 'Test not appropriate '
225 'in a venv')
226 def test_executable(self):
227 """
228 Test that the sys.executable value is as expected.
229 """
230 shutil.rmtree(self.env_dir)
231 self.run_with_capture(venv.create, self.env_dir)
232 envpy = os.path.join(os.path.realpath(self.env_dir), self.bindir, self.exe)
233 cmd = [envpy, '-c', 'import sys; print(sys.executable)']
234 p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
235 stderr=subprocess.PIPE)
236 out, err = p.communicate()
Antoine Pitrou9c92a692012-08-05 00:33:10 +0200237 self.assertEqual(out.strip(), envpy.encode())
Vinay Sajip90db6612012-07-17 17:33:46 +0100238
239 @unittest.skipUnless(can_symlink(), 'Needs symlinks')
240 def test_executable_symlinks(self):
241 """
242 Test that the sys.executable value is as expected.
243 """
244 shutil.rmtree(self.env_dir)
245 builder = venv.EnvBuilder(clear=True, symlinks=True)
246 builder.create(self.env_dir)
247 envpy = os.path.join(os.path.realpath(self.env_dir), self.bindir, self.exe)
248 cmd = [envpy, '-c', 'import sys; print(sys.executable)']
249 p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
250 stderr=subprocess.PIPE)
251 out, err = p.communicate()
Antoine Pitrou9c92a692012-08-05 00:33:10 +0200252 self.assertEqual(out.strip(), envpy.encode())
Vinay Sajip7ded1f02012-05-26 03:45:29 +0100253
254def test_main():
255 run_unittest(BasicTest)
256
257if __name__ == "__main__":
258 test_main()