Update to 2.7.3
[profile/ivi/python.git] / Lib / distutils / tests / test_sdist.py
1 """Tests for distutils.command.sdist."""
2 import os
3 import tarfile
4 import unittest
5 import warnings
6 import zipfile
7 from os.path import join
8 from textwrap import dedent
9
10 # zlib is not used here, but if it's not available
11 # the tests that use zipfile may fail
12 try:
13     import zlib
14 except ImportError:
15     zlib = None
16
17 try:
18     import grp
19     import pwd
20     UID_GID_SUPPORT = True
21 except ImportError:
22     UID_GID_SUPPORT = False
23
24 from test.test_support import captured_stdout, check_warnings, run_unittest
25
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
34
35 SETUP_PY = """
36 from distutils.core import setup
37 import somecode
38
39 setup(name='fake')
40 """
41
42 MANIFEST = """\
43 # file GENERATED by distutils, do NOT edit
44 README
45 buildout.cfg
46 inroot.txt
47 setup.py
48 data%(sep)sdata.dt
49 scripts%(sep)sscript.py
50 some%(sep)sfile.txt
51 some%(sep)sother_file.txt
52 somecode%(sep)s__init__.py
53 somecode%(sep)sdoc.dat
54 somecode%(sep)sdoc.txt
55 """
56
57 class SDistTestCase(PyPIRCCommandTestCase):
58
59     def setUp(self):
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)
72
73     def tearDown(self):
74         # back to normal
75         os.chdir(self.old_path)
76         super(SDistTestCase, self).tearDown()
77
78     def get_cmd(self, metadata=None):
79         """Returns a cmd"""
80         if metadata is 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
88         cmd = sdist(dist)
89         cmd.dist_dir = 'dist'
90         return dist, cmd
91
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
96         # on all systems
97
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')
101
102         os.mkdir(join(self.tmp_dir, 'somecode', '.hg'))
103         self.write_file((self.tmp_dir, 'somecode', '.hg',
104                          'ok'), 'xxx')
105
106         os.mkdir(join(self.tmp_dir, 'somecode', '.git'))
107         self.write_file((self.tmp_dir, 'somecode', '.git',
108                          'ok'), 'xxx')
109
110         # now building a sdist
111         dist, cmd = self.get_cmd()
112
113         # zip is available universally
114         # (tar might not be installed under win32)
115         cmd.formats = ['zip']
116
117         cmd.ensure_finalized()
118         cmd.run()
119
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'])
124
125         zip_file = zipfile.ZipFile(join(dist_folder, 'fake-1.0.zip'))
126         try:
127             content = zip_file.namelist()
128         finally:
129             zip_file.close()
130
131         # making sure everything has been pruned correctly
132         self.assertEqual(len(content), 4)
133
134     @unittest.skipUnless(zlib, "requires zlib")
135     def test_make_distribution(self):
136
137         # check if tar and gzip are installed
138         if (find_executable('tar') is None or
139             find_executable('gzip') is None):
140             return
141
142         # now building a sdist
143         dist, cmd = self.get_cmd()
144
145         # creating a gztar then a tar
146         cmd.formats = ['gztar', 'tar']
147         cmd.ensure_finalized()
148         cmd.run()
149
150         # making sure we have two files
151         dist_folder = join(self.tmp_dir, 'dist')
152         result = os.listdir(dist_folder)
153         result.sort()
154         self.assertEqual(result, ['fake-1.0.tar', 'fake-1.0.tar.gz'])
155
156         os.remove(join(dist_folder, 'fake-1.0.tar'))
157         os.remove(join(dist_folder, 'fake-1.0.tar.gz'))
158
159         # now trying a tar then a gztar
160         cmd.formats = ['tar', 'gztar']
161
162         cmd.ensure_finalized()
163         cmd.run()
164
165         result = os.listdir(dist_folder)
166         result.sort()
167         self.assertEqual(result, ['fake-1.0.tar', 'fake-1.0.tar.gz'])
168
169     @unittest.skipUnless(zlib, "requires zlib")
170     def test_unicode_metadata_tgz(self):
171         """
172         Unicode name or version should not break building to tar.gz format.
173         Reference issue #11638.
174         """
175
176         # create the sdist command with unicode parameters
177         dist, cmd = self.get_cmd({'name': u'fake', 'version': u'1.0'})
178
179         # create the sdist as gztar and run the command
180         cmd.formats = ['gztar']
181         cmd.ensure_finalized()
182         cmd.run()
183
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'])
188
189         os.remove(join(dist_folder, 'fake-1.0.tar.gz'))
190
191     @unittest.skipUnless(zlib, "requires zlib")
192     def test_add_defaults(self):
193
194         # http://bugs.python.org/issue2279
195
196         # add_default should also include
197         # data_files and package_data
198         dist, cmd = self.get_cmd()
199
200         # filling data_files by pointing files
201         # in package_data
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'), '#')
206
207         # adding some data in data_files
208         data_dir = join(self.tmp_dir, 'data')
209         os.mkdir(data_dir)
210         self.write_file((data_dir, 'data.dt'), '#')
211         some_dir = join(self.tmp_dir, 'some')
212         os.mkdir(some_dir)
213         # make sure VCS directories are pruned (#14004)
214         hg_dir = join(self.tmp_dir, '.hg')
215         os.mkdir(hg_dir)
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'), '#')
222
223         dist.data_files = [('data', ['data/data.dt',
224                                      'buildout.cfg',
225                                      'inroot.txt',
226                                      'notexisting']),
227                            'some/file.txt',
228                            'some/other_file.txt']
229
230         # adding a script
231         script_dir = join(self.tmp_dir, 'scripts')
232         os.mkdir(script_dir)
233         self.write_file((script_dir, 'script.py'), '#')
234         dist.scripts = [join('scripts', 'script.py')]
235
236         cmd.formats = ['zip']
237         cmd.use_defaults = True
238
239         cmd.ensure_finalized()
240         cmd.run()
241
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'])
246
247         zip_file = zipfile.ZipFile(join(dist_folder, 'fake-1.0.zip'))
248         try:
249             content = zip_file.namelist()
250         finally:
251             zip_file.close()
252
253         # making sure everything was added
254         self.assertEqual(len(content), 12)
255
256         # checking the MANIFEST
257         f = open(join(self.tmp_dir, 'MANIFEST'))
258         try:
259             manifest = f.read()
260         finally:
261             f.close()
262         self.assertEqual(manifest, MANIFEST % {'sep': os.sep})
263
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={})
268
269         # this should raise some warnings !
270         # with the `check` subcommand
271         cmd.ensure_finalized()
272         cmd.run()
273         warnings = [msg for msg in self.get_logs(WARN) if
274                     msg.startswith('warning: check:')]
275         self.assertEqual(len(warnings), 2)
276
277         # trying with a complete set of metadata
278         self.clear_logs()
279         dist, cmd = self.get_cmd()
280         cmd.ensure_finalized()
281         cmd.metadata_check = 0
282         cmd.run()
283         warnings = [msg for msg in self.get_logs(WARN) if
284                     msg.startswith('warning: check:')]
285         self.assertEqual(len(warnings), 0)
286
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")
292             cmd.check_metadata()
293             self.assertEqual(len(w.warnings), 1)
294
295     def test_show_formats(self):
296         with captured_stdout() as stdout:
297             show_formats()
298
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)
304
305     def test_finalize_options(self):
306         dist, cmd = self.get_cmd()
307         cmd.finalize_options()
308
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')
313
314         # formats has to be a string splitable on (' ', ',') or
315         # a stringlist
316         cmd.formats = 1
317         self.assertRaises(DistutilsOptionError, cmd.finalize_options)
318         cmd.formats = ['zip']
319         cmd.finalize_options()
320
321         # formats has to be known
322         cmd.formats = 'supazipa'
323         self.assertRaises(DistutilsOptionError, cmd.finalize_options)
324
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):
328
329         # check if tar and gzip are installed
330         if (find_executable('tar') is None or
331             find_executable('gzip') is None):
332             return
333
334         # now building a sdist
335         dist, cmd = self.get_cmd()
336
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()
342         cmd.run()
343
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)
347         try:
348             for member in archive.getmembers():
349                 self.assertEqual(member.uid, 0)
350                 self.assertEqual(member.gid, 0)
351         finally:
352             archive.close()
353
354         # building a sdist again
355         dist, cmd = self.get_cmd()
356
357         # creating a gztar
358         cmd.formats = ['gztar']
359         cmd.ensure_finalized()
360         cmd.run()
361
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)
365
366         # note that we are not testing the group ownership here
367         # because, depending on the platforms and the container
368         # rights (see #7408)
369         try:
370             for member in archive.getmembers():
371                 self.assertEqual(member.uid, os.getuid())
372         finally:
373             archive.close()
374
375     # the following tests make sure there is a nice error message instead
376     # of a traceback when parsing an invalid manifest template
377
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()
384         cmd.read_template()
385         warnings = self.get_logs(WARN)
386         self.assertEqual(len(warnings), 1)
387
388     def test_invalid_template_unknown_command(self):
389         self._test_template('taunt knights *')
390
391     def test_invalid_template_wrong_arguments(self):
392         # this manifest command takes one argument
393         self._test_template('prune')
394
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/')
400
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()
405
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()
411         cmd.run()
412
413         f = open(cmd.manifest)
414         try:
415             manifest = [line.strip() for line in f.read().split('\n')
416                         if line.strip() != '']
417         finally:
418             f.close()
419
420         self.assertEqual(len(manifest), 5)
421
422         # adding a file
423         self.write_file((self.tmp_dir, 'somecode', 'doc2.txt'), '#')
424
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()
429
430         cmd.run()
431
432         f = open(cmd.manifest)
433         try:
434             manifest2 = [line.strip() for line in f.read().split('\n')
435                          if line.strip() != '']
436         finally:
437             f.close()
438
439         # do we have the new file in MANIFEST ?
440         self.assertEqual(len(manifest2), 6)
441         self.assertIn('doc2.txt', manifest2[-1])
442
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()
448         cmd.run()
449
450         f = open(cmd.manifest)
451         try:
452             manifest = [line.strip() for line in f.read().split('\n')
453                         if line.strip() != '']
454         finally:
455             f.close()
456
457         self.assertEqual(manifest[0],
458                          '# file GENERATED by distutils, do NOT edit')
459
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("""\
464             # bad.py
465             #bad.py
466             good.py
467             """)
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!")
474         cmd.run()
475         self.assertEqual(cmd.filelist.files, ['good.py'])
476
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.')
486         cmd.run()
487         self.assertEqual(cmd.filelist.files, ['README.manual'])
488
489         f = open(cmd.manifest)
490         try:
491             manifest = [line.strip() for line in f.read().split('\n')
492                         if line.strip() != '']
493         finally:
494             f.close()
495
496         self.assertEqual(manifest, ['README.manual'])
497
498         archive_name = join(self.tmp_dir, 'dist', 'fake-1.0.tar.gz')
499         archive = tarfile.open(archive_name)
500         try:
501             filenames = [tarinfo.name for tarinfo in archive]
502         finally:
503             archive.close()
504         self.assertEqual(sorted(filenames), ['fake-1.0', 'fake-1.0/PKG-INFO',
505                                              'fake-1.0/README.manual'])
506
507 def test_suite():
508     return unittest.makeSuite(SDistTestCase)
509
510 if __name__ == "__main__":
511     run_unittest(test_suite())