Home | History | Annotate | Download | only in tests
      1 """Tests for distutils.command.sdist."""
      2 import os
      3 import unittest
      4 import shutil
      5 import zipfile
      6 import tarfile
      7 
      8 # zlib is not used here, but if it's not available

      9 # the tests that use zipfile may fail

     10 try:
     11     import zlib
     12 except ImportError:
     13     zlib = None
     14 
     15 try:
     16     import grp
     17     import pwd
     18     UID_GID_SUPPORT = True
     19 except ImportError:
     20     UID_GID_SUPPORT = False
     21 
     22 from os.path import join
     23 import sys
     24 import tempfile
     25 import warnings
     26 
     27 from test.test_support import captured_stdout, check_warnings, run_unittest
     28 
     29 from distutils.command.sdist import sdist, show_formats
     30 from distutils.core import Distribution
     31 from distutils.tests.test_config import PyPIRCCommandTestCase
     32 from distutils.errors import DistutilsExecError, DistutilsOptionError
     33 from distutils.spawn import find_executable
     34 from distutils.tests import support
     35 from distutils.log import WARN
     36 from distutils.archive_util import ARCHIVE_FORMATS
     37 
     38 SETUP_PY = """
     39 from distutils.core import setup
     40 import somecode
     41 
     42 setup(name='fake')
     43 """
     44 
     45 MANIFEST = """\
     46 # file GENERATED by distutils, do NOT edit
     47 README
     48 inroot.txt
     49 setup.py
     50 data%(sep)sdata.dt
     51 scripts%(sep)sscript.py
     52 some%(sep)sfile.txt
     53 some%(sep)sother_file.txt
     54 somecode%(sep)s__init__.py
     55 somecode%(sep)sdoc.dat
     56 somecode%(sep)sdoc.txt
     57 """
     58 
     59 class SDistTestCase(PyPIRCCommandTestCase):
     60 
     61     def setUp(self):
     62         # PyPIRCCommandTestCase creates a temp dir already

     63         # and put it in self.tmp_dir

     64         super(SDistTestCase, self).setUp()
     65         # setting up an environment

     66         self.old_path = os.getcwd()
     67         os.mkdir(join(self.tmp_dir, 'somecode'))
     68         os.mkdir(join(self.tmp_dir, 'dist'))
     69         # a package, and a README

     70         self.write_file((self.tmp_dir, 'README'), 'xxx')
     71         self.write_file((self.tmp_dir, 'somecode', '__init__.py'), '#')
     72         self.write_file((self.tmp_dir, 'setup.py'), SETUP_PY)
     73         os.chdir(self.tmp_dir)
     74 
     75     def tearDown(self):
     76         # back to normal

     77         os.chdir(self.old_path)
     78         super(SDistTestCase, self).tearDown()
     79 
     80     def get_cmd(self, metadata=None):
     81         """Returns a cmd"""
     82         if metadata is None:
     83             metadata = {'name': 'fake', 'version': '1.0',
     84                         'url': 'xxx', 'author': 'xxx',
     85                         'author_email': 'xxx'}
     86         dist = Distribution(metadata)
     87         dist.script_name = 'setup.py'
     88         dist.packages = ['somecode']
     89         dist.include_package_data = True
     90         cmd = sdist(dist)
     91         cmd.dist_dir = 'dist'
     92         def _warn(*args):
     93             pass
     94         cmd.warn = _warn
     95         return dist, cmd
     96 
     97     @unittest.skipUnless(zlib, "requires zlib")
     98     def test_prune_file_list(self):
     99         # this test creates a package with some vcs dirs in it

    100         # and launch sdist to make sure they get pruned

    101         # on all systems

    102 
    103         # creating VCS directories with some files in them

    104         os.mkdir(join(self.tmp_dir, 'somecode', '.svn'))
    105         self.write_file((self.tmp_dir, 'somecode', '.svn', 'ok.py'), 'xxx')
    106 
    107         os.mkdir(join(self.tmp_dir, 'somecode', '.hg'))
    108         self.write_file((self.tmp_dir, 'somecode', '.hg',
    109                          'ok'), 'xxx')
    110 
    111         os.mkdir(join(self.tmp_dir, 'somecode', '.git'))
    112         self.write_file((self.tmp_dir, 'somecode', '.git',
    113                          'ok'), 'xxx')
    114 
    115         # now building a sdist

    116         dist, cmd = self.get_cmd()
    117 
    118         # zip is available universally

    119         # (tar might not be installed under win32)

    120         cmd.formats = ['zip']
    121 
    122         cmd.ensure_finalized()
    123         cmd.run()
    124 
    125         # now let's check what we have

    126         dist_folder = join(self.tmp_dir, 'dist')
    127         files = os.listdir(dist_folder)
    128         self.assertEqual(files, ['fake-1.0.zip'])
    129 
    130         zip_file = zipfile.ZipFile(join(dist_folder, 'fake-1.0.zip'))
    131         try:
    132             content = zip_file.namelist()
    133         finally:
    134             zip_file.close()
    135 
    136         # making sure everything has been pruned correctly

    137         self.assertEqual(len(content), 4)
    138 
    139     @unittest.skipUnless(zlib, "requires zlib")
    140     def test_make_distribution(self):
    141 
    142         # check if tar and gzip are installed

    143         if (find_executable('tar') is None or
    144             find_executable('gzip') is None):
    145             return
    146 
    147         # now building a sdist

    148         dist, cmd = self.get_cmd()
    149 
    150         # creating a gztar then a tar

    151         cmd.formats = ['gztar', 'tar']
    152         cmd.ensure_finalized()
    153         cmd.run()
    154 
    155         # making sure we have two files

    156         dist_folder = join(self.tmp_dir, 'dist')
    157         result = os.listdir(dist_folder)
    158         result.sort()
    159         self.assertEqual(result, ['fake-1.0.tar', 'fake-1.0.tar.gz'] )
    160 
    161         os.remove(join(dist_folder, 'fake-1.0.tar'))
    162         os.remove(join(dist_folder, 'fake-1.0.tar.gz'))
    163 
    164         # now trying a tar then a gztar

    165         cmd.formats = ['tar', 'gztar']
    166 
    167         cmd.ensure_finalized()
    168         cmd.run()
    169 
    170         result = os.listdir(dist_folder)
    171         result.sort()
    172         self.assertEqual(result, ['fake-1.0.tar', 'fake-1.0.tar.gz'])
    173 
    174     @unittest.skipUnless(zlib, "requires zlib")
    175     def test_add_defaults(self):
    176 
    177         # http://bugs.python.org/issue2279

    178 
    179         # add_default should also include

    180         # data_files and package_data

    181         dist, cmd = self.get_cmd()
    182 
    183         # filling data_files by pointing files

    184         # in package_data

    185         dist.package_data = {'': ['*.cfg', '*.dat'],
    186                              'somecode': ['*.txt']}
    187         self.write_file((self.tmp_dir, 'somecode', 'doc.txt'), '#')
    188         self.write_file((self.tmp_dir, 'somecode', 'doc.dat'), '#')
    189 
    190         # adding some data in data_files

    191         data_dir = join(self.tmp_dir, 'data')
    192         os.mkdir(data_dir)
    193         self.write_file((data_dir, 'data.dt'), '#')
    194         some_dir = join(self.tmp_dir, 'some')
    195         os.mkdir(some_dir)
    196         self.write_file((self.tmp_dir, 'inroot.txt'), '#')
    197         self.write_file((some_dir, 'file.txt'), '#')
    198         self.write_file((some_dir, 'other_file.txt'), '#')
    199 
    200         dist.data_files = [('data', ['data/data.dt',
    201                                      'inroot.txt',
    202                                      'notexisting']),
    203                            'some/file.txt',
    204                            'some/other_file.txt']
    205 
    206         # adding a script

    207         script_dir = join(self.tmp_dir, 'scripts')
    208         os.mkdir(script_dir)
    209         self.write_file((script_dir, 'script.py'), '#')
    210         dist.scripts = [join('scripts', 'script.py')]
    211 
    212         cmd.formats = ['zip']
    213         cmd.use_defaults = True
    214 
    215         cmd.ensure_finalized()
    216         cmd.run()
    217 
    218         # now let's check what we have

    219         dist_folder = join(self.tmp_dir, 'dist')
    220         files = os.listdir(dist_folder)
    221         self.assertEqual(files, ['fake-1.0.zip'])
    222 
    223         zip_file = zipfile.ZipFile(join(dist_folder, 'fake-1.0.zip'))
    224         try:
    225             content = zip_file.namelist()
    226         finally:
    227             zip_file.close()
    228 
    229         # making sure everything was added

    230         self.assertEqual(len(content), 11)
    231 
    232         # checking the MANIFEST

    233         f = open(join(self.tmp_dir, 'MANIFEST'))
    234         try:
    235             manifest = f.read()
    236             self.assertEqual(manifest, MANIFEST % {'sep': os.sep})
    237         finally:
    238             f.close()
    239 
    240     @unittest.skipUnless(zlib, "requires zlib")
    241     def test_metadata_check_option(self):
    242         # testing the `medata-check` option

    243         dist, cmd = self.get_cmd(metadata={})
    244 
    245         # this should raise some warnings !

    246         # with the `check` subcommand

    247         cmd.ensure_finalized()
    248         cmd.run()
    249         warnings = self.get_logs(WARN)
    250         self.assertEqual(len(warnings), 2)
    251 
    252         # trying with a complete set of metadata

    253         self.clear_logs()
    254         dist, cmd = self.get_cmd()
    255         cmd.ensure_finalized()
    256         cmd.metadata_check = 0
    257         cmd.run()
    258         warnings = self.get_logs(WARN)
    259         self.assertEqual(len(warnings), 0)
    260 
    261     def test_check_metadata_deprecated(self):
    262         # makes sure make_metadata is deprecated

    263         dist, cmd = self.get_cmd()
    264         with check_warnings() as w:
    265             warnings.simplefilter("always")
    266             cmd.check_metadata()
    267             self.assertEqual(len(w.warnings), 1)
    268 
    269     def test_show_formats(self):
    270         with captured_stdout() as stdout:
    271             show_formats()
    272 
    273         # the output should be a header line + one line per format

    274         num_formats = len(ARCHIVE_FORMATS.keys())
    275         output = [line for line in stdout.getvalue().split('\n')
    276                   if line.strip().startswith('--formats=')]
    277         self.assertEqual(len(output), num_formats)
    278 
    279     def test_finalize_options(self):
    280 
    281         dist, cmd = self.get_cmd()
    282         cmd.finalize_options()
    283 
    284         # default options set by finalize

    285         self.assertEqual(cmd.manifest, 'MANIFEST')
    286         self.assertEqual(cmd.template, 'MANIFEST.in')
    287         self.assertEqual(cmd.dist_dir, 'dist')
    288 
    289         # formats has to be a string splitable on (' ', ',') or

    290         # a stringlist

    291         cmd.formats = 1
    292         self.assertRaises(DistutilsOptionError, cmd.finalize_options)
    293         cmd.formats = ['zip']
    294         cmd.finalize_options()
    295 
    296         # formats has to be known

    297         cmd.formats = 'supazipa'
    298         self.assertRaises(DistutilsOptionError, cmd.finalize_options)
    299 
    300     @unittest.skipUnless(zlib, "requires zlib")
    301     @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
    302     def test_make_distribution_owner_group(self):
    303 
    304         # check if tar and gzip are installed

    305         if (find_executable('tar') is None or
    306             find_executable('gzip') is None):
    307             return
    308 
    309         # now building a sdist

    310         dist, cmd = self.get_cmd()
    311 
    312         # creating a gztar and specifying the owner+group

    313         cmd.formats = ['gztar']
    314         cmd.owner = pwd.getpwuid(0)[0]
    315         cmd.group = grp.getgrgid(0)[0]
    316         cmd.ensure_finalized()
    317         cmd.run()
    318 
    319         # making sure we have the good rights

    320         archive_name = join(self.tmp_dir, 'dist', 'fake-1.0.tar.gz')
    321         archive = tarfile.open(archive_name)
    322         try:
    323             for member in archive.getmembers():
    324                 self.assertEqual(member.uid, 0)
    325                 self.assertEqual(member.gid, 0)
    326         finally:
    327             archive.close()
    328 
    329         # building a sdist again

    330         dist, cmd = self.get_cmd()
    331 
    332         # creating a gztar

    333         cmd.formats = ['gztar']
    334         cmd.ensure_finalized()
    335         cmd.run()
    336 
    337         # making sure we have the good rights

    338         archive_name = join(self.tmp_dir, 'dist', 'fake-1.0.tar.gz')
    339         archive = tarfile.open(archive_name)
    340 
    341         # note that we are not testing the group ownership here

    342         # because, depending on the platforms and the container

    343         # rights (see #7408)

    344         try:
    345             for member in archive.getmembers():
    346                 self.assertEqual(member.uid, os.getuid())
    347         finally:
    348             archive.close()
    349 
    350     @unittest.skipUnless(zlib, "requires zlib")
    351     def test_get_file_list(self):
    352         # make sure MANIFEST is recalculated

    353         dist, cmd = self.get_cmd()
    354 
    355         # filling data_files by pointing files in package_data

    356         dist.package_data = {'somecode': ['*.txt']}
    357         self.write_file((self.tmp_dir, 'somecode', 'doc.txt'), '#')
    358         cmd.ensure_finalized()
    359         cmd.run()
    360 
    361         f = open(cmd.manifest)
    362         try:
    363             manifest = [line.strip() for line in f.read().split('\n')
    364                         if line.strip() != '']
    365         finally:
    366             f.close()
    367 
    368         self.assertEqual(len(manifest), 5)
    369 
    370         # adding a file

    371         self.write_file((self.tmp_dir, 'somecode', 'doc2.txt'), '#')
    372 
    373         # make sure build_py is reinitialized, like a fresh run

    374         build_py = dist.get_command_obj('build_py')
    375         build_py.finalized = False
    376         build_py.ensure_finalized()
    377 
    378         cmd.run()
    379 
    380         f = open(cmd.manifest)
    381         try:
    382             manifest2 = [line.strip() for line in f.read().split('\n')
    383                          if line.strip() != '']
    384         finally:
    385             f.close()
    386 
    387         # do we have the new file in MANIFEST ?

    388         self.assertEqual(len(manifest2), 6)
    389         self.assertIn('doc2.txt', manifest2[-1])
    390 
    391     @unittest.skipUnless(zlib, "requires zlib")
    392     def test_manifest_marker(self):
    393         # check that autogenerated MANIFESTs have a marker

    394         dist, cmd = self.get_cmd()
    395         cmd.ensure_finalized()
    396         cmd.run()
    397 
    398         f = open(cmd.manifest)
    399         try:
    400             manifest = [line.strip() for line in f.read().split('\n')
    401                         if line.strip() != '']
    402         finally:
    403             f.close()
    404 
    405         self.assertEqual(manifest[0],
    406                          '# file GENERATED by distutils, do NOT edit')
    407 
    408     @unittest.skipUnless(zlib, "requires zlib")
    409     def test_manual_manifest(self):
    410         # check that a MANIFEST without a marker is left alone

    411         dist, cmd = self.get_cmd()
    412         cmd.ensure_finalized()
    413         self.write_file((self.tmp_dir, cmd.manifest), 'README.manual')
    414         cmd.run()
    415 
    416         f = open(cmd.manifest)
    417         try:
    418             manifest = [line.strip() for line in f.read().split('\n')
    419                         if line.strip() != '']
    420         finally:
    421             f.close()
    422 
    423         self.assertEqual(manifest, ['README.manual'])
    424 
    425 def test_suite():
    426     return unittest.makeSuite(SDistTestCase)
    427 
    428 if __name__ == "__main__":
    429     run_unittest(test_suite())
    430