1 """Tests for distutils.command.sdist."""
7 from os.path import join
8 from textwrap import dedent
10 # zlib is not used here, but if it's not available
11 # the tests that use zipfile may fail
20 UID_GID_SUPPORT = True
22 UID_GID_SUPPORT = False
24 from test.test_support import captured_stdout, check_warnings, run_unittest
26 from distutils.command.sdist import sdist, show_formats
27 from distutils.core import Distribution
28 from distutils.tests.test_config import PyPIRCCommandTestCase
29 from distutils.errors import DistutilsOptionError
30 from distutils.spawn import find_executable
31 from distutils.log import WARN
32 from distutils.filelist import FileList
33 from distutils.archive_util import ARCHIVE_FORMATS
36 from distutils.core import setup
43 # file GENERATED by distutils, do NOT edit
49 scripts%(sep)sscript.py
51 some%(sep)sother_file.txt
52 somecode%(sep)s__init__.py
53 somecode%(sep)sdoc.dat
54 somecode%(sep)sdoc.txt
57 class SDistTestCase(PyPIRCCommandTestCase):
60 # PyPIRCCommandTestCase creates a temp dir already
61 # and put it in self.tmp_dir
62 super(SDistTestCase, self).setUp()
63 # setting up an environment
64 self.old_path = os.getcwd()
65 os.mkdir(join(self.tmp_dir, 'somecode'))
66 os.mkdir(join(self.tmp_dir, 'dist'))
67 # a package, and a README
68 self.write_file((self.tmp_dir, 'README'), 'xxx')
69 self.write_file((self.tmp_dir, 'somecode', '__init__.py'), '#')
70 self.write_file((self.tmp_dir, 'setup.py'), SETUP_PY)
71 os.chdir(self.tmp_dir)
75 os.chdir(self.old_path)
76 super(SDistTestCase, self).tearDown()
78 def get_cmd(self, metadata=None):
81 metadata = {'name': 'fake', 'version': '1.0',
82 'url': 'xxx', 'author': 'xxx',
83 'author_email': 'xxx'}
84 dist = Distribution(metadata)
85 dist.script_name = 'setup.py'
86 dist.packages = ['somecode']
87 dist.include_package_data = True
92 @unittest.skipUnless(zlib, "requires zlib")
93 def test_prune_file_list(self):
94 # this test creates a package with some vcs dirs in it
95 # and launch sdist to make sure they get pruned
98 # creating VCS directories with some files in them
99 os.mkdir(join(self.tmp_dir, 'somecode', '.svn'))
100 self.write_file((self.tmp_dir, 'somecode', '.svn', 'ok.py'), 'xxx')
102 os.mkdir(join(self.tmp_dir, 'somecode', '.hg'))
103 self.write_file((self.tmp_dir, 'somecode', '.hg',
106 os.mkdir(join(self.tmp_dir, 'somecode', '.git'))
107 self.write_file((self.tmp_dir, 'somecode', '.git',
110 # now building a sdist
111 dist, cmd = self.get_cmd()
113 # zip is available universally
114 # (tar might not be installed under win32)
115 cmd.formats = ['zip']
117 cmd.ensure_finalized()
120 # now let's check what we have
121 dist_folder = join(self.tmp_dir, 'dist')
122 files = os.listdir(dist_folder)
123 self.assertEqual(files, ['fake-1.0.zip'])
125 zip_file = zipfile.ZipFile(join(dist_folder, 'fake-1.0.zip'))
127 content = zip_file.namelist()
131 # making sure everything has been pruned correctly
132 self.assertEqual(len(content), 4)
134 @unittest.skipUnless(zlib, "requires zlib")
135 def test_make_distribution(self):
137 # check if tar and gzip are installed
138 if (find_executable('tar') is None or
139 find_executable('gzip') is None):
142 # now building a sdist
143 dist, cmd = self.get_cmd()
145 # creating a gztar then a tar
146 cmd.formats = ['gztar', 'tar']
147 cmd.ensure_finalized()
150 # making sure we have two files
151 dist_folder = join(self.tmp_dir, 'dist')
152 result = os.listdir(dist_folder)
154 self.assertEqual(result, ['fake-1.0.tar', 'fake-1.0.tar.gz'])
156 os.remove(join(dist_folder, 'fake-1.0.tar'))
157 os.remove(join(dist_folder, 'fake-1.0.tar.gz'))
159 # now trying a tar then a gztar
160 cmd.formats = ['tar', 'gztar']
162 cmd.ensure_finalized()
165 result = os.listdir(dist_folder)
167 self.assertEqual(result, ['fake-1.0.tar', 'fake-1.0.tar.gz'])
169 @unittest.skipUnless(zlib, "requires zlib")
170 def test_unicode_metadata_tgz(self):
172 Unicode name or version should not break building to tar.gz format.
173 Reference issue #11638.
176 # create the sdist command with unicode parameters
177 dist, cmd = self.get_cmd({'name': u'fake', 'version': u'1.0'})
179 # create the sdist as gztar and run the command
180 cmd.formats = ['gztar']
181 cmd.ensure_finalized()
184 # The command should have created the .tar.gz file
185 dist_folder = join(self.tmp_dir, 'dist')
186 result = os.listdir(dist_folder)
187 self.assertEqual(result, ['fake-1.0.tar.gz'])
189 os.remove(join(dist_folder, 'fake-1.0.tar.gz'))
191 @unittest.skipUnless(zlib, "requires zlib")
192 def test_add_defaults(self):
194 # http://bugs.python.org/issue2279
196 # add_default should also include
197 # data_files and package_data
198 dist, cmd = self.get_cmd()
200 # filling data_files by pointing files
202 dist.package_data = {'': ['*.cfg', '*.dat'],
203 'somecode': ['*.txt']}
204 self.write_file((self.tmp_dir, 'somecode', 'doc.txt'), '#')
205 self.write_file((self.tmp_dir, 'somecode', 'doc.dat'), '#')
207 # adding some data in data_files
208 data_dir = join(self.tmp_dir, 'data')
210 self.write_file((data_dir, 'data.dt'), '#')
211 some_dir = join(self.tmp_dir, 'some')
213 # make sure VCS directories are pruned (#14004)
214 hg_dir = join(self.tmp_dir, '.hg')
216 self.write_file((hg_dir, 'last-message.txt'), '#')
217 # a buggy regex used to prevent this from working on windows (#6884)
218 self.write_file((self.tmp_dir, 'buildout.cfg'), '#')
219 self.write_file((self.tmp_dir, 'inroot.txt'), '#')
220 self.write_file((some_dir, 'file.txt'), '#')
221 self.write_file((some_dir, 'other_file.txt'), '#')
223 dist.data_files = [('data', ['data/data.dt',
228 'some/other_file.txt']
231 script_dir = join(self.tmp_dir, 'scripts')
233 self.write_file((script_dir, 'script.py'), '#')
234 dist.scripts = [join('scripts', 'script.py')]
236 cmd.formats = ['zip']
237 cmd.use_defaults = True
239 cmd.ensure_finalized()
242 # now let's check what we have
243 dist_folder = join(self.tmp_dir, 'dist')
244 files = os.listdir(dist_folder)
245 self.assertEqual(files, ['fake-1.0.zip'])
247 zip_file = zipfile.ZipFile(join(dist_folder, 'fake-1.0.zip'))
249 content = zip_file.namelist()
253 # making sure everything was added
254 self.assertEqual(len(content), 12)
256 # checking the MANIFEST
257 f = open(join(self.tmp_dir, 'MANIFEST'))
262 self.assertEqual(manifest, MANIFEST % {'sep': os.sep})
264 @unittest.skipUnless(zlib, "requires zlib")
265 def test_metadata_check_option(self):
266 # testing the `medata-check` option
267 dist, cmd = self.get_cmd(metadata={})
269 # this should raise some warnings !
270 # with the `check` subcommand
271 cmd.ensure_finalized()
273 warnings = [msg for msg in self.get_logs(WARN) if
274 msg.startswith('warning: check:')]
275 self.assertEqual(len(warnings), 2)
277 # trying with a complete set of metadata
279 dist, cmd = self.get_cmd()
280 cmd.ensure_finalized()
281 cmd.metadata_check = 0
283 warnings = [msg for msg in self.get_logs(WARN) if
284 msg.startswith('warning: check:')]
285 self.assertEqual(len(warnings), 0)
287 def test_check_metadata_deprecated(self):
288 # makes sure make_metadata is deprecated
289 dist, cmd = self.get_cmd()
290 with check_warnings() as w:
291 warnings.simplefilter("always")
293 self.assertEqual(len(w.warnings), 1)
295 def test_show_formats(self):
296 with captured_stdout() as stdout:
299 # the output should be a header line + one line per format
300 num_formats = len(ARCHIVE_FORMATS.keys())
301 output = [line for line in stdout.getvalue().split('\n')
302 if line.strip().startswith('--formats=')]
303 self.assertEqual(len(output), num_formats)
305 def test_finalize_options(self):
306 dist, cmd = self.get_cmd()
307 cmd.finalize_options()
309 # default options set by finalize
310 self.assertEqual(cmd.manifest, 'MANIFEST')
311 self.assertEqual(cmd.template, 'MANIFEST.in')
312 self.assertEqual(cmd.dist_dir, 'dist')
314 # formats has to be a string splitable on (' ', ',') or
317 self.assertRaises(DistutilsOptionError, cmd.finalize_options)
318 cmd.formats = ['zip']
319 cmd.finalize_options()
321 # formats has to be known
322 cmd.formats = 'supazipa'
323 self.assertRaises(DistutilsOptionError, cmd.finalize_options)
325 @unittest.skipUnless(zlib, "requires zlib")
326 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
327 def test_make_distribution_owner_group(self):
329 # check if tar and gzip are installed
330 if (find_executable('tar') is None or
331 find_executable('gzip') is None):
334 # now building a sdist
335 dist, cmd = self.get_cmd()
337 # creating a gztar and specifying the owner+group
338 cmd.formats = ['gztar']
339 cmd.owner = pwd.getpwuid(0)[0]
340 cmd.group = grp.getgrgid(0)[0]
341 cmd.ensure_finalized()
344 # making sure we have the good rights
345 archive_name = join(self.tmp_dir, 'dist', 'fake-1.0.tar.gz')
346 archive = tarfile.open(archive_name)
348 for member in archive.getmembers():
349 self.assertEqual(member.uid, 0)
350 self.assertEqual(member.gid, 0)
354 # building a sdist again
355 dist, cmd = self.get_cmd()
358 cmd.formats = ['gztar']
359 cmd.ensure_finalized()
362 # making sure we have the good rights
363 archive_name = join(self.tmp_dir, 'dist', 'fake-1.0.tar.gz')
364 archive = tarfile.open(archive_name)
366 # note that we are not testing the group ownership here
367 # because, depending on the platforms and the container
370 for member in archive.getmembers():
371 self.assertEqual(member.uid, os.getuid())
375 # the following tests make sure there is a nice error message instead
376 # of a traceback when parsing an invalid manifest template
378 def _test_template(self, content):
379 dist, cmd = self.get_cmd()
380 os.chdir(self.tmp_dir)
381 self.write_file('MANIFEST.in', content)
382 cmd.ensure_finalized()
383 cmd.filelist = FileList()
385 warnings = self.get_logs(WARN)
386 self.assertEqual(len(warnings), 1)
388 def test_invalid_template_unknown_command(self):
389 self._test_template('taunt knights *')
391 def test_invalid_template_wrong_arguments(self):
392 # this manifest command takes one argument
393 self._test_template('prune')
395 @unittest.skipIf(os.name != 'nt', 'test relevant for Windows only')
396 def test_invalid_template_wrong_path(self):
397 # on Windows, trailing slashes are not allowed
398 # this used to crash instead of raising a warning: #8286
399 self._test_template('include examples/')
401 @unittest.skipUnless(zlib, "requires zlib")
402 def test_get_file_list(self):
403 # make sure MANIFEST is recalculated
404 dist, cmd = self.get_cmd()
406 # filling data_files by pointing files in package_data
407 dist.package_data = {'somecode': ['*.txt']}
408 self.write_file((self.tmp_dir, 'somecode', 'doc.txt'), '#')
409 cmd.formats = ['gztar']
410 cmd.ensure_finalized()
413 f = open(cmd.manifest)
415 manifest = [line.strip() for line in f.read().split('\n')
416 if line.strip() != '']
420 self.assertEqual(len(manifest), 5)
423 self.write_file((self.tmp_dir, 'somecode', 'doc2.txt'), '#')
425 # make sure build_py is reinitialized, like a fresh run
426 build_py = dist.get_command_obj('build_py')
427 build_py.finalized = False
428 build_py.ensure_finalized()
432 f = open(cmd.manifest)
434 manifest2 = [line.strip() for line in f.read().split('\n')
435 if line.strip() != '']
439 # do we have the new file in MANIFEST ?
440 self.assertEqual(len(manifest2), 6)
441 self.assertIn('doc2.txt', manifest2[-1])
443 @unittest.skipUnless(zlib, "requires zlib")
444 def test_manifest_marker(self):
445 # check that autogenerated MANIFESTs have a marker
446 dist, cmd = self.get_cmd()
447 cmd.ensure_finalized()
450 f = open(cmd.manifest)
452 manifest = [line.strip() for line in f.read().split('\n')
453 if line.strip() != '']
457 self.assertEqual(manifest[0],
458 '# file GENERATED by distutils, do NOT edit')
460 @unittest.skipUnless(zlib, 'requires zlib')
461 def test_manifest_comments(self):
462 # make sure comments don't cause exceptions or wrong includes
463 contents = dedent("""\
468 dist, cmd = self.get_cmd()
469 cmd.ensure_finalized()
470 self.write_file((self.tmp_dir, cmd.manifest), contents)
471 self.write_file((self.tmp_dir, 'good.py'), '# pick me!')
472 self.write_file((self.tmp_dir, 'bad.py'), "# don't pick me!")
473 self.write_file((self.tmp_dir, '#bad.py'), "# don't pick me!")
475 self.assertEqual(cmd.filelist.files, ['good.py'])
477 @unittest.skipUnless(zlib, "requires zlib")
478 def test_manual_manifest(self):
479 # check that a MANIFEST without a marker is left alone
480 dist, cmd = self.get_cmd()
481 cmd.formats = ['gztar']
482 cmd.ensure_finalized()
483 self.write_file((self.tmp_dir, cmd.manifest), 'README.manual')
484 self.write_file((self.tmp_dir, 'README.manual'),
485 'This project maintains its MANIFEST file itself.')
487 self.assertEqual(cmd.filelist.files, ['README.manual'])
489 f = open(cmd.manifest)
491 manifest = [line.strip() for line in f.read().split('\n')
492 if line.strip() != '']
496 self.assertEqual(manifest, ['README.manual'])
498 archive_name = join(self.tmp_dir, 'dist', 'fake-1.0.tar.gz')
499 archive = tarfile.open(archive_name)
501 filenames = [tarinfo.name for tarinfo in archive]
504 self.assertEqual(sorted(filenames), ['fake-1.0', 'fake-1.0/PKG-INFO',
505 'fake-1.0/README.manual'])
508 return unittest.makeSuite(SDistTestCase)
510 if __name__ == "__main__":
511 run_unittest(test_suite())