536 lines
17 KiB
Python
536 lines
17 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""sdist tests"""
|
|
|
|
import locale
|
|
import os
|
|
import shutil
|
|
import sys
|
|
import tempfile
|
|
import unittest
|
|
import unicodedata
|
|
import re
|
|
from setuptools.tests import environment, test_svn
|
|
from setuptools.tests.py26compat import skipIf
|
|
|
|
from setuptools.compat import StringIO, unicode
|
|
from setuptools.tests.py26compat import skipIf
|
|
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 sys.version_info >= (3,):
|
|
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
|
|
def quiet():
|
|
global old_stdout, old_stderr
|
|
old_stdout, old_stderr = sys.stdout, sys.stderr
|
|
sys.stdout, sys.stderr = StringIO(), StringIO()
|
|
|
|
def unquiet():
|
|
sys.stdout, sys.stderr = old_stdout, old_stderr
|
|
|
|
|
|
# Fake byte literals for Python <= 2.5
|
|
def b(s, encoding='utf-8'):
|
|
if sys.version_info >= (3,):
|
|
return s.encode(encoding)
|
|
return s
|
|
|
|
|
|
# Convert to POSIX path
|
|
def posix(path):
|
|
if sys.version_info >= (3,) 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()
|
|
|
|
# squelch output
|
|
quiet()
|
|
try:
|
|
cmd.run()
|
|
finally:
|
|
unquiet()
|
|
|
|
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_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')
|
|
|
|
# Add UTF-8 filename and write manifest
|
|
quiet()
|
|
try:
|
|
mm.run()
|
|
mm.filelist.files.append(filename)
|
|
mm.write_manifest()
|
|
finally:
|
|
unquiet()
|
|
|
|
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 sys.version_info >= (3,):
|
|
self.assertTrue(posix(filename) in u_contents)
|
|
else:
|
|
self.assertTrue(posix(filename) in contents)
|
|
|
|
# Python 3 only
|
|
if sys.version_info >= (3,):
|
|
|
|
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'))
|
|
|
|
# Add filename and write manifest
|
|
quiet()
|
|
try:
|
|
mm.run()
|
|
u_filename = filename.decode('utf-8')
|
|
mm.filelist.files.append(u_filename)
|
|
# Re-write manifest
|
|
mm.write_manifest()
|
|
finally:
|
|
unquiet()
|
|
|
|
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):
|
|
# 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')
|
|
|
|
# Latin-1 filename
|
|
filename = os.path.join(b('sdist_test'), LATIN1_FILENAME)
|
|
|
|
# Add filename with surrogates and write manifest
|
|
quiet()
|
|
try:
|
|
mm.run()
|
|
u_filename = filename.decode('utf-8', 'surrogateescape')
|
|
mm.filelist.files.append(u_filename)
|
|
# Re-write manifest
|
|
mm.write_manifest()
|
|
finally:
|
|
unquiet()
|
|
|
|
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
|
|
quiet()
|
|
try:
|
|
cmd.run()
|
|
finally:
|
|
unquiet()
|
|
|
|
# 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 = []
|
|
quiet()
|
|
try:
|
|
cmd.read_manifest()
|
|
finally:
|
|
unquiet()
|
|
|
|
# The filelist should contain the UTF-8 filename
|
|
if sys.version_info >= (3,):
|
|
filename = filename.decode('utf-8')
|
|
self.assertTrue(filename in cmd.filelist.files)
|
|
|
|
# Python 3 only
|
|
if sys.version_info >= (3,):
|
|
|
|
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
|
|
quiet()
|
|
try:
|
|
cmd.run()
|
|
finally:
|
|
unquiet()
|
|
|
|
# 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 = []
|
|
quiet()
|
|
try:
|
|
try:
|
|
cmd.read_manifest()
|
|
except UnicodeDecodeError:
|
|
e = sys.exc_info()[1]
|
|
self.fail(e)
|
|
finally:
|
|
unquiet()
|
|
|
|
# The Latin-1 filename should have been skipped
|
|
filename = filename.decode('latin-1')
|
|
self.assertFalse(filename in cmd.filelist.files)
|
|
|
|
@skipIf(sys.version_info >= (3,) 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()
|
|
|
|
quiet()
|
|
try:
|
|
cmd.run()
|
|
finally:
|
|
unquiet()
|
|
|
|
if sys.platform == 'darwin':
|
|
filename = decompose(filename)
|
|
|
|
if sys.version_info >= (3,):
|
|
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))
|
|
|
|
quiet()
|
|
try:
|
|
cmd.run()
|
|
finally:
|
|
unquiet()
|
|
|
|
if sys.version_info >= (3,):
|
|
#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:
|
|
# No conversion takes place under Python 2 and the file
|
|
# is included. We shall keep it that way for BBB.
|
|
self.assertTrue(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__)
|