Index: recipe_engine/third_party/setuptools/tests/test_sdist.py |
diff --git a/recipe_engine/third_party/setuptools/tests/test_sdist.py b/recipe_engine/third_party/setuptools/tests/test_sdist.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..5f8a190f461902b2da93e51f755f282c9c7b581e |
--- /dev/null |
+++ b/recipe_engine/third_party/setuptools/tests/test_sdist.py |
@@ -0,0 +1,552 @@ |
+# -*- coding: utf-8 -*- |
+"""sdist tests""" |
+ |
+import locale |
+import os |
+import shutil |
+import sys |
+import tempfile |
+import unittest |
+import unicodedata |
+import re |
+import contextlib |
+from setuptools.tests import environment, test_svn |
+from setuptools.tests.py26compat import skipIf |
+ |
+from setuptools.compat import StringIO, unicode, PY3, PY2 |
+from setuptools.command.sdist import sdist, walk_revctrl |
+from setuptools.command.egg_info import manifest_maker |
+from setuptools.dist import Distribution |
+from setuptools import svn_utils |
+ |
+SETUP_ATTRS = { |
+ 'name': 'sdist_test', |
+ 'version': '0.0', |
+ 'packages': ['sdist_test'], |
+ 'package_data': {'sdist_test': ['*.txt']} |
+} |
+ |
+ |
+SETUP_PY = """\ |
+from setuptools import setup |
+ |
+setup(**%r) |
+""" % SETUP_ATTRS |
+ |
+ |
+if PY3: |
+ LATIN1_FILENAME = 'smörbröd.py'.encode('latin-1') |
+else: |
+ LATIN1_FILENAME = 'sm\xf6rbr\xf6d.py' |
+ |
+ |
+# Cannot use context manager because of Python 2.4 |
+@contextlib.contextmanager |
+def quiet(): |
+ old_stdout, old_stderr = sys.stdout, sys.stderr |
+ sys.stdout, sys.stderr = StringIO(), StringIO() |
+ try: |
+ yield |
+ finally: |
+ sys.stdout, sys.stderr = old_stdout, old_stderr |
+ |
+ |
+# Fake byte literals for Python <= 2.5 |
+def b(s, encoding='utf-8'): |
+ if PY3: |
+ return s.encode(encoding) |
+ return s |
+ |
+ |
+# Convert to POSIX path |
+def posix(path): |
+ if PY3 and not isinstance(path, str): |
+ return path.replace(os.sep.encode('ascii'), b('/')) |
+ else: |
+ return path.replace(os.sep, '/') |
+ |
+ |
+# HFS Plus uses decomposed UTF-8 |
+def decompose(path): |
+ if isinstance(path, unicode): |
+ return unicodedata.normalize('NFD', path) |
+ try: |
+ path = path.decode('utf-8') |
+ path = unicodedata.normalize('NFD', path) |
+ path = path.encode('utf-8') |
+ except UnicodeError: |
+ pass # Not UTF-8 |
+ return path |
+ |
+ |
+class TestSdistTest(unittest.TestCase): |
+ |
+ def setUp(self): |
+ self.temp_dir = tempfile.mkdtemp() |
+ f = open(os.path.join(self.temp_dir, 'setup.py'), 'w') |
+ f.write(SETUP_PY) |
+ f.close() |
+ |
+ # Set up the rest of the test package |
+ test_pkg = os.path.join(self.temp_dir, 'sdist_test') |
+ os.mkdir(test_pkg) |
+ # *.rst was not included in package_data, so c.rst should not be |
+ # automatically added to the manifest when not under version control |
+ for fname in ['__init__.py', 'a.txt', 'b.txt', 'c.rst']: |
+ # Just touch the files; their contents are irrelevant |
+ open(os.path.join(test_pkg, fname), 'w').close() |
+ |
+ self.old_cwd = os.getcwd() |
+ os.chdir(self.temp_dir) |
+ |
+ def tearDown(self): |
+ os.chdir(self.old_cwd) |
+ shutil.rmtree(self.temp_dir) |
+ |
+ def test_package_data_in_sdist(self): |
+ """Regression test for pull request #4: ensures that files listed in |
+ package_data are included in the manifest even if they're not added to |
+ version control. |
+ """ |
+ |
+ dist = Distribution(SETUP_ATTRS) |
+ dist.script_name = 'setup.py' |
+ cmd = sdist(dist) |
+ cmd.ensure_finalized() |
+ |
+ with quiet(): |
+ cmd.run() |
+ |
+ manifest = cmd.filelist.files |
+ self.assertTrue(os.path.join('sdist_test', 'a.txt') in manifest) |
+ self.assertTrue(os.path.join('sdist_test', 'b.txt') in manifest) |
+ self.assertTrue(os.path.join('sdist_test', 'c.rst') not in manifest) |
+ |
+ |
+ def test_defaults_case_sensitivity(self): |
+ """ |
+ Make sure default files (README.*, etc.) are added in a case-sensitive |
+ way to avoid problems with packages built on Windows. |
+ """ |
+ |
+ open(os.path.join(self.temp_dir, 'readme.rst'), 'w').close() |
+ open(os.path.join(self.temp_dir, 'SETUP.cfg'), 'w').close() |
+ |
+ dist = Distribution(SETUP_ATTRS) |
+ # the extension deliberately capitalized for this test |
+ # to make sure the actual filename (not capitalized) gets added |
+ # to the manifest |
+ dist.script_name = 'setup.PY' |
+ cmd = sdist(dist) |
+ cmd.ensure_finalized() |
+ |
+ with quiet(): |
+ cmd.run() |
+ |
+ # lowercase all names so we can test in a case-insensitive way to make sure the files are not included |
+ manifest = map(lambda x: x.lower(), cmd.filelist.files) |
+ self.assertFalse('readme.rst' in manifest, manifest) |
+ self.assertFalse('setup.py' in manifest, manifest) |
+ self.assertFalse('setup.cfg' in manifest, manifest) |
+ |
+ def test_manifest_is_written_with_utf8_encoding(self): |
+ # Test for #303. |
+ dist = Distribution(SETUP_ATTRS) |
+ dist.script_name = 'setup.py' |
+ mm = manifest_maker(dist) |
+ mm.manifest = os.path.join('sdist_test.egg-info', 'SOURCES.txt') |
+ os.mkdir('sdist_test.egg-info') |
+ |
+ # UTF-8 filename |
+ filename = os.path.join('sdist_test', 'smörbröd.py') |
+ |
+ # Must create the file or it will get stripped. |
+ open(filename, 'w').close() |
+ |
+ # Add UTF-8 filename and write manifest |
+ with quiet(): |
+ mm.run() |
+ mm.filelist.append(filename) |
+ mm.write_manifest() |
+ |
+ manifest = open(mm.manifest, 'rbU') |
+ contents = manifest.read() |
+ manifest.close() |
+ |
+ # The manifest should be UTF-8 encoded |
+ try: |
+ u_contents = contents.decode('UTF-8') |
+ except UnicodeDecodeError: |
+ e = sys.exc_info()[1] |
+ self.fail(e) |
+ |
+ # The manifest should contain the UTF-8 filename |
+ if PY2: |
+ fs_enc = sys.getfilesystemencoding() |
+ filename = filename.decode(fs_enc) |
+ |
+ self.assertTrue(posix(filename) in u_contents) |
+ |
+ # Python 3 only |
+ if PY3: |
+ |
+ def test_write_manifest_allows_utf8_filenames(self): |
+ # Test for #303. |
+ dist = Distribution(SETUP_ATTRS) |
+ dist.script_name = 'setup.py' |
+ mm = manifest_maker(dist) |
+ mm.manifest = os.path.join('sdist_test.egg-info', 'SOURCES.txt') |
+ os.mkdir('sdist_test.egg-info') |
+ |
+ # UTF-8 filename |
+ filename = os.path.join(b('sdist_test'), b('smörbröd.py')) |
+ |
+ # Must touch the file or risk removal |
+ open(filename, "w").close() |
+ |
+ # Add filename and write manifest |
+ with quiet(): |
+ mm.run() |
+ u_filename = filename.decode('utf-8') |
+ mm.filelist.files.append(u_filename) |
+ # Re-write manifest |
+ mm.write_manifest() |
+ |
+ manifest = open(mm.manifest, 'rbU') |
+ contents = manifest.read() |
+ manifest.close() |
+ |
+ # The manifest should be UTF-8 encoded |
+ try: |
+ contents.decode('UTF-8') |
+ except UnicodeDecodeError: |
+ e = sys.exc_info()[1] |
+ self.fail(e) |
+ |
+ # The manifest should contain the UTF-8 filename |
+ self.assertTrue(posix(filename) in contents) |
+ |
+ # The filelist should have been updated as well |
+ self.assertTrue(u_filename in mm.filelist.files) |
+ |
+ def test_write_manifest_skips_non_utf8_filenames(self): |
+ """ |
+ Files that cannot be encoded to UTF-8 (specifically, those that |
+ weren't originally successfully decoded and have surrogate |
+ escapes) should be omitted from the manifest. |
+ See https://bitbucket.org/tarek/distribute/issue/303 for history. |
+ """ |
+ dist = Distribution(SETUP_ATTRS) |
+ dist.script_name = 'setup.py' |
+ mm = manifest_maker(dist) |
+ mm.manifest = os.path.join('sdist_test.egg-info', 'SOURCES.txt') |
+ os.mkdir('sdist_test.egg-info') |
+ |
+ # Latin-1 filename |
+ filename = os.path.join(b('sdist_test'), LATIN1_FILENAME) |
+ |
+ # Add filename with surrogates and write manifest |
+ with quiet(): |
+ mm.run() |
+ u_filename = filename.decode('utf-8', 'surrogateescape') |
+ mm.filelist.append(u_filename) |
+ # Re-write manifest |
+ mm.write_manifest() |
+ |
+ manifest = open(mm.manifest, 'rbU') |
+ contents = manifest.read() |
+ manifest.close() |
+ |
+ # The manifest should be UTF-8 encoded |
+ try: |
+ contents.decode('UTF-8') |
+ except UnicodeDecodeError: |
+ e = sys.exc_info()[1] |
+ self.fail(e) |
+ |
+ # The Latin-1 filename should have been skipped |
+ self.assertFalse(posix(filename) in contents) |
+ |
+ # The filelist should have been updated as well |
+ self.assertFalse(u_filename in mm.filelist.files) |
+ |
+ def test_manifest_is_read_with_utf8_encoding(self): |
+ # Test for #303. |
+ dist = Distribution(SETUP_ATTRS) |
+ dist.script_name = 'setup.py' |
+ cmd = sdist(dist) |
+ cmd.ensure_finalized() |
+ |
+ # Create manifest |
+ with quiet(): |
+ cmd.run() |
+ |
+ # Add UTF-8 filename to manifest |
+ filename = os.path.join(b('sdist_test'), b('smörbröd.py')) |
+ cmd.manifest = os.path.join('sdist_test.egg-info', 'SOURCES.txt') |
+ manifest = open(cmd.manifest, 'ab') |
+ manifest.write(b('\n') + filename) |
+ manifest.close() |
+ |
+ # The file must exist to be included in the filelist |
+ open(filename, 'w').close() |
+ |
+ # Re-read manifest |
+ cmd.filelist.files = [] |
+ with quiet(): |
+ cmd.read_manifest() |
+ |
+ # The filelist should contain the UTF-8 filename |
+ if PY3: |
+ filename = filename.decode('utf-8') |
+ self.assertTrue(filename in cmd.filelist.files) |
+ |
+ # Python 3 only |
+ if PY3: |
+ |
+ def test_read_manifest_skips_non_utf8_filenames(self): |
+ # Test for #303. |
+ dist = Distribution(SETUP_ATTRS) |
+ dist.script_name = 'setup.py' |
+ cmd = sdist(dist) |
+ cmd.ensure_finalized() |
+ |
+ # Create manifest |
+ with quiet(): |
+ cmd.run() |
+ |
+ # Add Latin-1 filename to manifest |
+ filename = os.path.join(b('sdist_test'), LATIN1_FILENAME) |
+ cmd.manifest = os.path.join('sdist_test.egg-info', 'SOURCES.txt') |
+ manifest = open(cmd.manifest, 'ab') |
+ manifest.write(b('\n') + filename) |
+ manifest.close() |
+ |
+ # The file must exist to be included in the filelist |
+ open(filename, 'w').close() |
+ |
+ # Re-read manifest |
+ cmd.filelist.files = [] |
+ with quiet(): |
+ try: |
+ cmd.read_manifest() |
+ except UnicodeDecodeError: |
+ e = sys.exc_info()[1] |
+ self.fail(e) |
+ |
+ # The Latin-1 filename should have been skipped |
+ filename = filename.decode('latin-1') |
+ self.assertFalse(filename in cmd.filelist.files) |
+ |
+ @skipIf(PY3 and locale.getpreferredencoding() != 'UTF-8', |
+ 'Unittest fails if locale is not utf-8 but the manifests is recorded correctly') |
+ def test_sdist_with_utf8_encoded_filename(self): |
+ # Test for #303. |
+ dist = Distribution(SETUP_ATTRS) |
+ dist.script_name = 'setup.py' |
+ cmd = sdist(dist) |
+ cmd.ensure_finalized() |
+ |
+ # UTF-8 filename |
+ filename = os.path.join(b('sdist_test'), b('smörbröd.py')) |
+ open(filename, 'w').close() |
+ |
+ with quiet(): |
+ cmd.run() |
+ |
+ if sys.platform == 'darwin': |
+ filename = decompose(filename) |
+ |
+ if PY3: |
+ fs_enc = sys.getfilesystemencoding() |
+ |
+ if sys.platform == 'win32': |
+ if fs_enc == 'cp1252': |
+ # Python 3 mangles the UTF-8 filename |
+ filename = filename.decode('cp1252') |
+ self.assertTrue(filename in cmd.filelist.files) |
+ else: |
+ filename = filename.decode('mbcs') |
+ self.assertTrue(filename in cmd.filelist.files) |
+ else: |
+ filename = filename.decode('utf-8') |
+ self.assertTrue(filename in cmd.filelist.files) |
+ else: |
+ self.assertTrue(filename in cmd.filelist.files) |
+ |
+ def test_sdist_with_latin1_encoded_filename(self): |
+ # Test for #303. |
+ dist = Distribution(SETUP_ATTRS) |
+ dist.script_name = 'setup.py' |
+ cmd = sdist(dist) |
+ cmd.ensure_finalized() |
+ |
+ # Latin-1 filename |
+ filename = os.path.join(b('sdist_test'), LATIN1_FILENAME) |
+ open(filename, 'w').close() |
+ self.assertTrue(os.path.isfile(filename)) |
+ |
+ with quiet(): |
+ cmd.run() |
+ |
+ if PY3: |
+ # not all windows systems have a default FS encoding of cp1252 |
+ if sys.platform == 'win32': |
+ # Latin-1 is similar to Windows-1252 however |
+ # on mbcs filesys it is not in latin-1 encoding |
+ fs_enc = sys.getfilesystemencoding() |
+ if fs_enc == 'mbcs': |
+ filename = filename.decode('mbcs') |
+ else: |
+ filename = filename.decode('latin-1') |
+ |
+ self.assertTrue(filename in cmd.filelist.files) |
+ else: |
+ # The Latin-1 filename should have been skipped |
+ filename = filename.decode('latin-1') |
+ self.assertFalse(filename in cmd.filelist.files) |
+ else: |
+ # Under Python 2 there seems to be no decoded string in the |
+ # filelist. However, due to decode and encoding of the |
+ # file name to get utf-8 Manifest the latin1 maybe excluded |
+ try: |
+ # fs_enc should match how one is expect the decoding to |
+ # be proformed for the manifest output. |
+ fs_enc = sys.getfilesystemencoding() |
+ filename.decode(fs_enc) |
+ self.assertTrue(filename in cmd.filelist.files) |
+ except UnicodeDecodeError: |
+ self.assertFalse(filename in cmd.filelist.files) |
+ |
+class TestDummyOutput(environment.ZippedEnvironment): |
+ |
+ def setUp(self): |
+ self.datafile = os.path.join('setuptools', 'tests', |
+ 'svn_data', "dummy.zip") |
+ self.dataname = "dummy" |
+ super(TestDummyOutput, self).setUp() |
+ |
+ def _run(self): |
+ code, data = environment.run_setup_py(["sdist"], |
+ pypath=self.old_cwd, |
+ data_stream=0) |
+ if code: |
+ info = "DIR: " + os.path.abspath('.') |
+ info += "\n SDIST RETURNED: %i\n\n" % code |
+ info += data |
+ raise AssertionError(info) |
+ |
+ datalines = data.splitlines() |
+ |
+ possible = ( |
+ "running sdist", |
+ "running egg_info", |
+ "creating dummy\.egg-info", |
+ "writing dummy\.egg-info", |
+ "writing top-level names to dummy\.egg-info", |
+ "writing dependency_links to dummy\.egg-info", |
+ "writing manifest file 'dummy\.egg-info", |
+ "reading manifest file 'dummy\.egg-info", |
+ "reading manifest template 'MANIFEST\.in'", |
+ "writing manifest file 'dummy\.egg-info", |
+ "creating dummy-0.1.1", |
+ "making hard links in dummy-0\.1\.1", |
+ "copying files to dummy-0\.1\.1", |
+ "copying \S+ -> dummy-0\.1\.1", |
+ "copying dummy", |
+ "copying dummy\.egg-info", |
+ "hard linking \S+ -> dummy-0\.1\.1", |
+ "hard linking dummy", |
+ "hard linking dummy\.egg-info", |
+ "Writing dummy-0\.1\.1", |
+ "creating dist", |
+ "creating 'dist", |
+ "Creating tar archive", |
+ "running check", |
+ "adding 'dummy-0\.1\.1", |
+ "tar .+ dist/dummy-0\.1\.1\.tar dummy-0\.1\.1", |
+ "gzip .+ dist/dummy-0\.1\.1\.tar", |
+ "removing 'dummy-0\.1\.1' \\(and everything under it\\)", |
+ ) |
+ |
+ print(" DIR: " + os.path.abspath('.')) |
+ for line in datalines: |
+ found = False |
+ for pattern in possible: |
+ if re.match(pattern, line): |
+ print(" READ: " + line) |
+ found = True |
+ break |
+ if not found: |
+ raise AssertionError("Unexpexected: %s\n-in-\n%s" |
+ % (line, data)) |
+ |
+ return data |
+ |
+ def test_sources(self): |
+ self._run() |
+ |
+ |
+class TestSvn(environment.ZippedEnvironment): |
+ |
+ def setUp(self): |
+ version = svn_utils.SvnInfo.get_svn_version() |
+ if not version: # None or Empty |
+ return |
+ |
+ self.base_version = tuple([int(x) for x in version.split('.')][:2]) |
+ |
+ if not self.base_version: |
+ raise ValueError('No SVN tools installed') |
+ elif self.base_version < (1, 3): |
+ raise ValueError('Insufficient SVN Version %s' % version) |
+ elif self.base_version >= (1, 9): |
+ # trying the latest version |
+ self.base_version = (1, 8) |
+ |
+ self.dataname = "svn%i%i_example" % self.base_version |
+ self.datafile = os.path.join('setuptools', 'tests', |
+ 'svn_data', self.dataname + ".zip") |
+ super(TestSvn, self).setUp() |
+ |
+ @skipIf(not test_svn._svn_check, "No SVN to text, in the first place") |
+ def test_walksvn(self): |
+ if self.base_version >= (1, 6): |
+ folder2 = 'third party2' |
+ folder3 = 'third party3' |
+ else: |
+ folder2 = 'third_party2' |
+ folder3 = 'third_party3' |
+ |
+ # TODO is this right |
+ expected = set([ |
+ os.path.join('a file'), |
+ os.path.join(folder2, 'Changes.txt'), |
+ os.path.join(folder2, 'MD5SUMS'), |
+ os.path.join(folder2, 'README.txt'), |
+ os.path.join(folder3, 'Changes.txt'), |
+ os.path.join(folder3, 'MD5SUMS'), |
+ os.path.join(folder3, 'README.txt'), |
+ os.path.join(folder3, 'TODO.txt'), |
+ os.path.join(folder3, 'fin'), |
+ os.path.join('third_party', 'README.txt'), |
+ os.path.join('folder', folder2, 'Changes.txt'), |
+ os.path.join('folder', folder2, 'MD5SUMS'), |
+ os.path.join('folder', folder2, 'WatashiNiYomimasu.txt'), |
+ os.path.join('folder', folder3, 'Changes.txt'), |
+ os.path.join('folder', folder3, 'fin'), |
+ os.path.join('folder', folder3, 'MD5SUMS'), |
+ os.path.join('folder', folder3, 'oops'), |
+ os.path.join('folder', folder3, 'WatashiNiYomimasu.txt'), |
+ os.path.join('folder', folder3, 'ZuMachen.txt'), |
+ os.path.join('folder', 'third_party', 'WatashiNiYomimasu.txt'), |
+ os.path.join('folder', 'lalala.txt'), |
+ os.path.join('folder', 'quest.txt'), |
+ # The example will have a deleted file |
+ # (or should) but shouldn't return it |
+ ]) |
+ self.assertEqual(set(x for x in walk_revctrl()), expected) |
+ |
+ |
+def test_suite(): |
+ return unittest.defaultTestLoader.loadTestsFromName(__name__) |