"""Tests for packaging.command.sdist.""" import os import zipfile import tarfile import logging from packaging.tests.support import requires_zlib try: import grp import pwd UID_GID_SUPPORT = True except ImportError: UID_GID_SUPPORT = False from os.path import join from packaging.tests import captured_stdout from packaging.command.sdist import sdist from packaging.command.sdist import show_formats from packaging.dist import Distribution from packaging.tests import unittest from packaging.errors import PackagingOptionError from packaging.util import find_executable from packaging.tests import support from shutil import get_archive_formats SETUP_PY = """ from packaging.core import setup import somecode setup(name='fake') """ MANIFEST = """\ # file GENERATED by packaging, do NOT edit inroot.txt data%(sep)sdata.dt scripts%(sep)sscript.py some%(sep)sfile.txt some%(sep)sother_file.txt somecode%(sep)s__init__.py somecode%(sep)sdoc.dat somecode%(sep)sdoc.txt """ def builder(dist, filelist): filelist.append('bah') class SDistTestCase(support.TempdirManager, support.LoggingCatcher, support.EnvironRestorer, unittest.TestCase): restore_environ = ['HOME'] def setUp(self): # PyPIRCCommandTestCase creates a temp dir already # and put it in self.tmp_dir super(SDistTestCase, self).setUp() self.tmp_dir = self.mkdtemp() os.environ['HOME'] = self.tmp_dir # setting up an environment self.old_path = os.getcwd() os.mkdir(join(self.tmp_dir, 'somecode')) os.mkdir(join(self.tmp_dir, 'dist')) # a package, and a README self.write_file((self.tmp_dir, 'README'), 'xxx') self.write_file((self.tmp_dir, 'somecode', '__init__.py'), '#') self.write_file((self.tmp_dir, 'setup.py'), SETUP_PY) os.chdir(self.tmp_dir) def tearDown(self): # back to normal os.chdir(self.old_path) super(SDistTestCase, self).tearDown() def get_cmd(self, metadata=None): """Returns a cmd""" if metadata is None: metadata = {'name': 'fake', 'version': '1.0', 'url': 'xxx', 'author': 'xxx', 'author_email': 'xxx'} dist = Distribution(metadata) dist.script_name = 'setup.py' dist.packages = ['somecode'] dist.include_package_data = True cmd = sdist(dist) cmd.dist_dir = 'dist' return dist, cmd @requires_zlib def test_prune_file_list(self): # this test creates a package with some vcs dirs in it # and launch sdist to make sure they get pruned # on all systems # creating VCS directories with some files in them os.mkdir(join(self.tmp_dir, 'somecode', '.svn')) self.write_file((self.tmp_dir, 'somecode', '.svn', 'ok.py'), 'xxx') os.mkdir(join(self.tmp_dir, 'somecode', '.hg')) self.write_file((self.tmp_dir, 'somecode', '.hg', 'ok'), 'xxx') os.mkdir(join(self.tmp_dir, 'somecode', '.git')) self.write_file((self.tmp_dir, 'somecode', '.git', 'ok'), 'xxx') # now building a sdist dist, cmd = self.get_cmd() # zip is available universally # (tar might not be installed under win32) cmd.formats = ['zip'] cmd.ensure_finalized() cmd.run() # now let's check what we have dist_folder = join(self.tmp_dir, 'dist') files = os.listdir(dist_folder) self.assertEqual(files, ['fake-1.0.zip']) with zipfile.ZipFile(join(dist_folder, 'fake-1.0.zip')) as zip_file: content = zip_file.namelist() # making sure everything has been pruned correctly self.assertEqual(len(content), 2) @requires_zlib @unittest.skipIf(find_executable('tar') is None or find_executable('gzip') is None, 'requires tar and gzip programs') def test_make_distribution(self): # building a sdist dist, cmd = self.get_cmd() # creating a gztar then a tar cmd.formats = ['gztar', 'tar'] cmd.ensure_finalized() cmd.run() # making sure we have two files dist_folder = join(self.tmp_dir, 'dist') result = sorted(os.listdir(dist_folder)) self.assertEqual(result, ['fake-1.0.tar', 'fake-1.0.tar.gz']) os.remove(join(dist_folder, 'fake-1.0.tar')) os.remove(join(dist_folder, 'fake-1.0.tar.gz')) # now trying a tar then a gztar cmd.formats = ['tar', 'gztar'] cmd.ensure_finalized() cmd.run() result = sorted(os.listdir(dist_folder)) self.assertEqual(result, ['fake-1.0.tar', 'fake-1.0.tar.gz']) @requires_zlib def test_add_defaults(self): # http://bugs.python.org/issue2279 # add_default should also include # data_files and package_data dist, cmd = self.get_cmd() # filling data_files by pointing files # in package_data dist.package_data = {'': ['*.cfg', '*.dat'], 'somecode': ['*.txt']} self.write_file((self.tmp_dir, 'somecode', 'doc.txt'), '#') self.write_file((self.tmp_dir, 'somecode', 'doc.dat'), '#') # adding some data in data_files data_dir = join(self.tmp_dir, 'data') os.mkdir(data_dir) self.write_file((data_dir, 'data.dt'), '#') some_dir = join(self.tmp_dir, 'some') os.mkdir(some_dir) self.write_file((self.tmp_dir, 'inroot.txt'), '#') self.write_file((some_dir, 'file.txt'), '#') self.write_file((some_dir, 'other_file.txt'), '#') dist.data_files = {'data/data.dt': '{appdata}/data.dt', 'inroot.txt': '{appdata}/inroot.txt', 'some/file.txt': '{appdata}/file.txt', 'some/other_file.txt': '{appdata}/other_file.txt'} # adding a script script_dir = join(self.tmp_dir, 'scripts') os.mkdir(script_dir) self.write_file((script_dir, 'script.py'), '#') dist.scripts = [join('scripts', 'script.py')] cmd.formats = ['zip'] cmd.use_defaults = True cmd.ensure_finalized() cmd.run() # now let's check what we have dist_folder = join(self.tmp_dir, 'dist') files = os.listdir(dist_folder) self.assertEqual(files, ['fake-1.0.zip']) with zipfile.ZipFile(join(dist_folder, 'fake-1.0.zip')) as zip_file: content = zip_file.namelist() # Making sure everything was added. This includes 8 code and data # files in addition to PKG-INFO. self.assertEqual(len(content), 9) # Checking the MANIFEST with open(join(self.tmp_dir, 'MANIFEST')) as fp: manifest = fp.read() self.assertEqual(manifest, MANIFEST % {'sep': os.sep}) @requires_zlib def test_metadata_check_option(self): # testing the `check-metadata` option dist, cmd = self.get_cmd(metadata={'name': 'xxx', 'version': 'xxx'}) # this should raise some warnings # with the check subcommand cmd.ensure_finalized() cmd.run() warnings = self.get_logs(logging.WARN) self.assertEqual(len(warnings), 3) # trying with a complete set of metadata self.loghandler.flush() dist, cmd = self.get_cmd() cmd.ensure_finalized() cmd.metadata_check = False cmd.run() warnings = self.get_logs(logging.WARN) # removing manifest generated warnings warnings = [warn for warn in warnings if not warn.endswith('-- skipping')] # the remaining warning is about the use of the default file list self.assertEqual(len(warnings), 1) def test_show_formats(self): __, stdout = captured_stdout(show_formats) # the output should be a header line + one line per format num_formats = len(get_archive_formats()) output = [line for line in stdout.split('\n') if line.strip().startswith('--formats=')] self.assertEqual(len(output), num_formats) def test_finalize_options(self): dist, cmd = self.get_cmd() cmd.finalize_options() # default options set by finalize self.assertEqual(cmd.manifest, 'MANIFEST') self.assertEqual(cmd.dist_dir, 'dist') # formats has to be a string splitable on (' ', ',') or # a stringlist cmd.formats = 1 self.assertRaises(PackagingOptionError, cmd.finalize_options) cmd.formats = ['zip'] cmd.finalize_options() # formats has to be known cmd.formats = 'supazipa' self.assertRaises(PackagingOptionError, cmd.finalize_options) @requires_zlib @unittest.skipUnless(UID_GID_SUPPORT, "requires grp and pwd support") @unittest.skipIf(find_executable('tar') is None or find_executable('gzip') is None, 'requires tar and gzip programs') def test_make_distribution_owner_group(self): # building a sdist dist, cmd = self.get_cmd() # creating a gztar and specifying the owner+group cmd.formats = ['gztar'] cmd.owner = pwd.getpwuid(0)[0] cmd.group = grp.getgrgid(0)[0] cmd.ensure_finalized() cmd.run() # making sure we have the good rights archive_name = join(self.tmp_dir, 'dist', 'fake-1.0.tar.gz') with tarfile.open(archive_name) as archive: for member in archive.getmembers(): self.assertEqual(member.uid, 0) self.assertEqual(member.gid, 0) # building a sdist again dist, cmd = self.get_cmd() # creating a gztar cmd.formats = ['gztar'] cmd.ensure_finalized() cmd.run() # making sure we have the good rights archive_name = join(self.tmp_dir, 'dist', 'fake-1.0.tar.gz') with tarfile.open(archive_name) as archive: # note that we are not testing the group ownership here # because, depending on the platforms and the container # rights (see #7408) for member in archive.getmembers(): self.assertEqual(member.uid, os.getuid()) @requires_zlib def test_get_file_list(self): # make sure MANIFEST is recalculated dist, cmd = self.get_cmd() # filling data_files by pointing files in package_data dist.package_data = {'somecode': ['*.txt']} self.write_file((self.tmp_dir, 'somecode', 'doc.txt'), '#') cmd.ensure_finalized() cmd.run() # Should produce four lines. Those lines are one comment, one default # (README) and two package files. with open(cmd.manifest) as f: manifest = [line.strip() for line in f.read().split('\n') if line.strip() != ''] self.assertEqual(len(manifest), 3) # Adding a file self.write_file((self.tmp_dir, 'somecode', 'doc2.txt'), '#') # make sure build_py is reinitialized, like a fresh run build_py = dist.get_command_obj('build_py') build_py.finalized = False build_py.ensure_finalized() cmd.run() with open(cmd.manifest) as f: manifest2 = [line.strip() for line in f.read().split('\n') if line.strip() != ''] # Do we have the new file in MANIFEST? self.assertEqual(len(manifest2), 4) self.assertIn('doc2.txt', manifest2[-1]) @requires_zlib def test_manifest_marker(self): # check that autogenerated MANIFESTs have a marker dist, cmd = self.get_cmd() cmd.ensure_finalized() cmd.run() with open(cmd.manifest) as f: manifest = [line.strip() for line in f.read().split('\n') if line.strip() != ''] self.assertEqual(manifest[0], '# file GENERATED by packaging, do NOT edit') @requires_zlib def test_manual_manifest(self): # check that a MANIFEST without a marker is left alone dist, cmd = self.get_cmd() cmd.ensure_finalized() self.write_file((self.tmp_dir, cmd.manifest), 'README.manual') cmd.run() with open(cmd.manifest) as f: manifest = [line.strip() for line in f.read().split('\n') if line.strip() != ''] self.assertEqual(manifest, ['README.manual']) @requires_zlib def test_template(self): dist, cmd = self.get_cmd() dist.extra_files = ['include yeah'] cmd.ensure_finalized() self.write_file((self.tmp_dir, 'yeah'), 'xxx') cmd.run() with open(cmd.manifest) as f: content = f.read() self.assertIn('yeah', content) @requires_zlib def test_manifest_builder(self): dist, cmd = self.get_cmd() cmd.manifest_builders = 'packaging.tests.test_command_sdist.builder' cmd.ensure_finalized() cmd.run() self.assertIn('bah', cmd.filelist.files) def test_suite(): return unittest.makeSuite(SDistTestCase) if __name__ == "__main__": unittest.main(defaultTest="test_suite")