diff options
Diffstat (limited to 'setuptools')
| -rwxr-xr-x | setuptools/archive_util.py | 3 | ||||
| -rw-r--r-- | setuptools/command/bdist_egg.py | 12 | ||||
| -rw-r--r-- | setuptools/command/build_py.py | 6 | ||||
| -rwxr-xr-x | setuptools/command/easy_install.py | 5 | ||||
| -rwxr-xr-x | setuptools/command/egg_info.py | 39 | ||||
| -rwxr-xr-x | setuptools/command/sdist.py | 32 | ||||
| -rw-r--r-- | setuptools/command/test.py | 17 | ||||
| -rw-r--r-- | setuptools/command/upload_docs.py | 125 | ||||
| -rw-r--r-- | setuptools/dist.py | 37 | ||||
| -rwxr-xr-x | setuptools/package_index.py | 60 | ||||
| -rw-r--r-- | setuptools/tests/test_dist_info.py | 14 | ||||
| -rw-r--r-- | setuptools/tests/test_markerlib.py | 40 | ||||
| -rw-r--r-- | setuptools/tests/test_sdist.py | 322 | ||||
| -rw-r--r-- | setuptools/tests/test_upload_docs.py | 15 |
14 files changed, 600 insertions, 127 deletions
diff --git a/setuptools/archive_util.py b/setuptools/archive_util.py index 5787753f..e22b25c0 100755 --- a/setuptools/archive_util.py +++ b/setuptools/archive_util.py @@ -158,6 +158,9 @@ def unpack_zipfile(filename, extract_dir, progress_filter=default_filter): finally: f.close() del data + unix_attributes = info.external_attr >> 16 + if unix_attributes: + os.chmod(target, unix_attributes) finally: z.close() diff --git a/setuptools/command/bdist_egg.py b/setuptools/command/bdist_egg.py index 0ee9c55b..17fae984 100644 --- a/setuptools/command/bdist_egg.py +++ b/setuptools/command/bdist_egg.py @@ -425,12 +425,12 @@ def scan_module(egg_dir, base, name, stubs): return True # Extension module pkg = base[len(egg_dir)+1:].replace(os.sep,'.') module = pkg+(pkg and '.' or '')+os.path.splitext(name)[0] - f = open(filename,'rb'); f.read(8) # skip magic & date - try: - code = marshal.load(f); f.close() - except ValueError: - f.seek(0); f.read(12) # skip magic & date & file size; file size added in Python 3.3 - code = marshal.load(f); f.close() + if sys.version_info < (3, 3): + skip = 8 # skip magic & date + else: + skip = 12 # skip magic & date & file size + f = open(filename,'rb'); f.read(skip) + code = marshal.load(f); f.close() safe = True symbols = dict.fromkeys(iter_symbols(code)) for bad in ['__file__', '__path__']: diff --git a/setuptools/command/build_py.py b/setuptools/command/build_py.py index 505dd4f3..8751acd4 100644 --- a/setuptools/command/build_py.py +++ b/setuptools/command/build_py.py @@ -51,10 +51,8 @@ try: if self.distribution.use_2to3_exclude_fixers is not None: excluded_fixers.extend(self.distribution.use_2to3_exclude_fixers) for fixer_name in excluded_fixers: - if fixer_name not in self.fixer_names: - log.warn("Excluded fixer %s not found", fixer_name) - continue - self.fixer_names.remove(fixer_name) + if fixer_name in self.fixer_names: + self.fixer_names.remove(fixer_name) except ImportError: class Mixin2to3: diff --git a/setuptools/command/easy_install.py b/setuptools/command/easy_install.py index f2260236..337532bc 100755 --- a/setuptools/command/easy_install.py +++ b/setuptools/command/easy_install.py @@ -1522,7 +1522,10 @@ def get_exe_prefixes(exe_filename): if name.endswith('-nspkg.pth'): continue if parts[0].upper() in ('PURELIB','PLATLIB'): - for pth in yield_lines(z.read(name)): + contents = z.read(name) + if sys.version_info >= (3,): + contents = contents.decode() + for pth in yield_lines(contents): pth = pth.strip().replace('\\','/') if not pth.startswith('import'): prefixes.append((('%s/%s/' % (parts[0],pth)), '')) diff --git a/setuptools/command/egg_info.py b/setuptools/command/egg_info.py index 46cdf4e0..0c2ea0cc 100755 --- a/setuptools/command/egg_info.py +++ b/setuptools/command/egg_info.py @@ -9,7 +9,7 @@ from distutils.errors import * from distutils import log from setuptools.command.sdist import sdist from distutils.util import convert_path -from distutils.filelist import FileList +from distutils.filelist import FileList as _FileList from pkg_resources import parse_requirements, safe_name, parse_version, \ safe_version, yield_lines, EntryPoint, iter_entry_points, to_filename from sdist import walk_revctrl @@ -162,7 +162,12 @@ class egg_info(Command): os.unlink(filename) def tagged_version(self): - return safe_version(self.distribution.get_version() + self.vtags) + version = self.distribution.get_version() + # egg_info may be called more than once for a distribution, + # in which case the version string already contains all tags. + if self.vtags and version.endswith(self.vtags): + return safe_version(version) + return safe_version(version + self.vtags) def run(self): self.mkpath(self.egg_info) @@ -269,16 +274,28 @@ class egg_info(Command): self.broken_egg_info = self.egg_info self.egg_info = bei # make it work for now -class FileList(FileList): +class FileList(_FileList): """File list that accepts only existing, platform-independent paths""" def append(self, item): if item.endswith('\r'): # Fix older sdists built on Windows item = item[:-1] path = convert_path(item) - if os.path.exists(path): - self.files.append(path) + if sys.version_info >= (3,): + try: + if os.path.exists(path) or os.path.exists(path.encode('utf-8')): + self.files.append(path) + except UnicodeEncodeError: + # Accept UTF-8 filenames even if LANG=C + if os.path.exists(path.encode('utf-8')): + self.files.append(path) + else: + log.warn("'%s' not %s encodable -- skipping", path, + sys.getfilesystemencoding()) + else: + if os.path.exists(path): + self.files.append(path) @@ -318,6 +335,18 @@ class manifest_maker(sdist): by 'add_defaults()' and 'read_template()') to the manifest file named by 'self.manifest'. """ + # The manifest must be UTF-8 encodable. See #303. + if sys.version_info >= (3,): + files = [] + for file in self.filelist.files: + try: + file.encode("utf-8") + except UnicodeEncodeError: + log.warn("'%s' not UTF-8 encodable -- skipping" % file) + else: + files.append(file) + self.filelist.files = files + files = self.filelist.files if os.sep!='/': files = [f.replace(os.sep,'/') for f in files] diff --git a/setuptools/command/sdist.py b/setuptools/command/sdist.py index a176f635..2fa3771a 100755 --- a/setuptools/command/sdist.py +++ b/setuptools/command/sdist.py @@ -262,7 +262,39 @@ class sdist(_sdist): self.get_finalized_command('egg_info').save_version_info(dest) + def _manifest_is_not_generated(self): + # check for special comment used in 2.7.1 and higher + if not os.path.isfile(self.manifest): + return False + fp = open(self.manifest, 'rbU') + try: + first_line = fp.readline() + finally: + fp.close() + return first_line != '# file GENERATED by distutils, do NOT edit\n'.encode() + + def read_manifest(self): + """Read the manifest file (named by 'self.manifest') and use it to + fill in 'self.filelist', the list of files to include in the source + distribution. + """ + log.info("reading manifest file '%s'", self.manifest) + manifest = open(self.manifest, 'rbU') + for line in manifest: + # The manifest must contain UTF-8. See #303. + if sys.version_info >= (3,): + try: + line = line.decode('UTF-8') + except UnicodeDecodeError: + log.warn("%r not UTF-8 decodable -- skipping" % line) + continue + # ignore comments and blank lines + line = line.strip() + if line.startswith('#') or not line: + continue + self.filelist.append(line) + manifest.close() diff --git a/setuptools/command/test.py b/setuptools/command/test.py index e5cb9bb5..a02ac142 100644 --- a/setuptools/command/test.py +++ b/setuptools/command/test.py @@ -2,6 +2,7 @@ from setuptools import Command from distutils.errors import DistutilsOptionError import sys from pkg_resources import * +from pkg_resources import _namespace_packages from unittest import TestLoader, main class ScanningLoader(TestLoader): @@ -139,6 +140,22 @@ class test(Command): def run_tests(self): import unittest + + # Purge modules under test from sys.modules. The test loader will + # re-import them from the build location. Required when 2to3 is used + # with namespace packages. + if sys.version_info >= (3,) and getattr(self.distribution, 'use_2to3', False): + module = self.test_args[-1].split('.')[0] + if module in _namespace_packages: + del_modules = [] + if module in sys.modules: + del_modules.append(module) + module += '.' + for name in sys.modules: + if name.startswith(module): + del_modules.append(name) + map(sys.modules.__delitem__, del_modules) + loader_ep = EntryPoint.parse("x="+self.test_loader) loader_class = loader_ep.load(require=False) cks = loader_class() diff --git a/setuptools/command/upload_docs.py b/setuptools/command/upload_docs.py index 213f7b58..98fb7233 100644 --- a/setuptools/command/upload_docs.py +++ b/setuptools/command/upload_docs.py @@ -9,10 +9,13 @@ import os import socket import zipfile import httplib -import base64 import urlparse import tempfile import sys +import shutil + +from base64 import standard_b64encode +from pkg_resources import iter_entry_points from distutils import log from distutils.errors import DistutilsOptionError @@ -22,20 +25,13 @@ try: except ImportError: from setuptools.command.upload import upload -_IS_PYTHON3 = sys.version > '3' - -try: - bytes -except NameError: - bytes = str -def b(str_or_bytes): - """Return bytes by either encoding the argument as ASCII or simply return - the argument as-is.""" - if not isinstance(str_or_bytes, bytes): - return str_or_bytes.encode('ascii') - else: - return str_or_bytes +# This is not just a replacement for byte literals +# but works as a general purpose encoder +def b(s, encoding='utf-8'): + if isinstance(s, unicode): + return s.encode(encoding) + return s class upload_docs(upload): @@ -51,40 +47,62 @@ class upload_docs(upload): ] boolean_options = upload.boolean_options + def has_sphinx(self): + if self.upload_dir is None: + for ep in iter_entry_points('distutils.commands', 'build_sphinx'): + return True + + sub_commands = [('build_sphinx', has_sphinx)] + def initialize_options(self): upload.initialize_options(self) self.upload_dir = None + self.target_dir = None def finalize_options(self): upload.finalize_options(self) if self.upload_dir is None: - build = self.get_finalized_command('build') - self.upload_dir = os.path.join(build.build_base, 'docs') - self.mkpath(self.upload_dir) - self.ensure_dirname('upload_dir') - self.announce('Using upload directory %s' % self.upload_dir) + if self.has_sphinx(): + build_sphinx = self.get_finalized_command('build_sphinx') + self.target_dir = build_sphinx.builder_target_dir + else: + build = self.get_finalized_command('build') + self.target_dir = os.path.join(build.build_base, 'docs') + else: + self.ensure_dirname('upload_dir') + self.target_dir = self.upload_dir + self.announce('Using upload directory %s' % self.target_dir) - def create_zipfile(self): - name = self.distribution.metadata.get_name() - tmp_dir = tempfile.mkdtemp() - tmp_file = os.path.join(tmp_dir, "%s.zip" % name) - zip_file = zipfile.ZipFile(tmp_file, "w") - for root, dirs, files in os.walk(self.upload_dir): - if root == self.upload_dir and not files: - raise DistutilsOptionError( - "no files found in upload directory '%s'" - % self.upload_dir) - for name in files: - full = os.path.join(root, name) - relative = root[len(self.upload_dir):].lstrip(os.path.sep) - dest = os.path.join(relative, name) - zip_file.write(full, dest) - zip_file.close() - return tmp_file + def create_zipfile(self, filename): + zip_file = zipfile.ZipFile(filename, "w") + try: + self.mkpath(self.target_dir) # just in case + for root, dirs, files in os.walk(self.target_dir): + if root == self.target_dir and not files: + raise DistutilsOptionError( + "no files found in upload directory '%s'" + % self.target_dir) + for name in files: + full = os.path.join(root, name) + relative = root[len(self.target_dir):].lstrip(os.path.sep) + dest = os.path.join(relative, name) + zip_file.write(full, dest) + finally: + zip_file.close() def run(self): - zip_file = self.create_zipfile() - self.upload_file(zip_file) + # Run sub commands + for cmd_name in self.get_sub_commands(): + self.run_command(cmd_name) + + tmp_dir = tempfile.mkdtemp() + name = self.distribution.metadata.get_name() + zip_file = os.path.join(tmp_dir, "%s.zip" % name) + try: + self.create_zipfile(zip_file) + self.upload_file(zip_file) + finally: + shutil.rmtree(tmp_dir) def upload_file(self, filename): content = open(filename, 'rb').read() @@ -95,36 +113,33 @@ class upload_docs(upload): 'content': (os.path.basename(filename), content), } # set up the authentication - credentials = self.username + ':' + self.password - if _IS_PYTHON3: # base64 only works with bytes in Python 3. - encoded_creds = base64.encodebytes(credentials.encode('utf8')) - auth = bytes("Basic ") - else: - encoded_creds = base64.encodestring(credentials) - auth = "Basic " - auth += encoded_creds.strip() + credentials = b(self.username + ':' + self.password) + credentials = standard_b64encode(credentials) + if sys.version_info >= (3,): + credentials = credentials.decode('ascii') + auth = "Basic " + credentials # Build up the MIME payload for the POST data - boundary = b('--------------GHSKFJDLGDS7543FJKLFHRE75642756743254') - sep_boundary = b('\n--') + boundary + boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254' + sep_boundary = b('\n--') + b(boundary) end_boundary = sep_boundary + b('--') body = [] - for key, values in data.items(): + for key, values in data.iteritems(): + title = '\nContent-Disposition: form-data; name="%s"' % key # handle multiple entries for the same name if type(values) != type([]): values = [values] for value in values: if type(value) is tuple: - fn = b(';filename="%s"' % value[0]) + title += '; filename="%s"' % value[0] value = value[1] else: - fn = b("") + value = b(value) body.append(sep_boundary) - body.append(b('\nContent-Disposition: form-data; name="%s"'%key)) - body.append(fn) + body.append(b(title)) body.append(b("\n\n")) - body.append(b(value)) - if value and value[-1] == b('\r'): + body.append(value) + if value and value[-1:] == b('\r'): body.append(b('\n')) # write an extra newline (lurve Macs) body.append(end_boundary) body.append(b("\n")) diff --git a/setuptools/dist.py b/setuptools/dist.py index 2061c0a2..6236d5be 100644 --- a/setuptools/dist.py +++ b/setuptools/dist.py @@ -641,6 +641,43 @@ class Distribution(_Distribution): name = name[:-6] yield name + + def handle_display_options(self, option_order): + """If there were any non-global "display-only" options + (--help-commands or the metadata display options) on the command + line, display the requested info and return true; else return + false. + """ + import sys + + if sys.version_info < (3,) or self.help_commands: + return _Distribution.handle_display_options(self, option_order) + + # Stdout may be StringIO (e.g. in tests) + import io + if not isinstance(sys.stdout, io.TextIOWrapper): + return _Distribution.handle_display_options(self, option_order) + + # Don't wrap stdout if utf-8 is already the encoding. Provides + # workaround for #334. + if sys.stdout.encoding.lower() in ('utf-8', 'utf8'): + return _Distribution.handle_display_options(self, option_order) + + # Print metadata in UTF-8 no matter the platform + encoding = sys.stdout.encoding + errors = sys.stdout.errors + newline = sys.platform != 'win32' and '\n' or None + line_buffering = sys.stdout.line_buffering + + sys.stdout = io.TextIOWrapper( + sys.stdout.detach(), 'utf-8', errors, newline, line_buffering) + try: + return _Distribution.handle_display_options(self, option_order) + finally: + sys.stdout = io.TextIOWrapper( + sys.stdout.detach(), encoding, errors, newline, line_buffering) + + # Install it throughout the distutils for module in distutils.dist, distutils.core, distutils.cmd: module.Distribution = Distribution diff --git a/setuptools/package_index.py b/setuptools/package_index.py index d0896feb..0ee21e3b 100755 --- a/setuptools/package_index.py +++ b/setuptools/package_index.py @@ -657,6 +657,10 @@ class PackageIndex(Environment): # if scheme=='svn' or scheme.startswith('svn+'): return self._download_svn(url, filename) + elif scheme=='git' or scheme.startswith('git+'): + return self._download_git(url, filename) + elif scheme.startswith('hg+'): + return self._download_hg(url, filename) elif scheme=='file': return urllib.url2pathname(urlparse.urlparse(url)[2]) else: @@ -697,6 +701,55 @@ class PackageIndex(Environment): os.system("svn checkout -q %s %s" % (url, filename)) return filename + def _vcs_split_rev_from_url(self, url, pop_prefix=False): + scheme, netloc, path, query, frag = urlparse.urlsplit(url) + + scheme = scheme.split('+', 1)[-1] + + # Some fragment identification fails + path = path.split('#',1)[0] + + rev = None + if '@' in path: + path, rev = path.rsplit('@', 1) + + # Also, discard fragment + url = urlparse.urlunsplit((scheme, netloc, path, query, '')) + + return url, rev + + def _download_git(self, url, filename): + filename = filename.split('#',1)[0] + url, rev = self._vcs_split_rev_from_url(url, pop_prefix=True) + + self.info("Doing git clone from %s to %s", url, filename) + os.system("git clone --quiet %s %s" % (url, filename)) + + if rev is not None: + self.info("Checking out %s", rev) + os.system("(cd %s && git checkout --quiet %s)" % ( + filename, + rev, + )) + + return filename + + def _download_hg(self, url, filename): + filename = filename.split('#',1)[0] + url, rev = self._vcs_split_rev_from_url(url, pop_prefix=True) + + self.info("Doing hg clone from %s to %s", url, filename) + os.system("hg clone --quiet %s %s" % (url, filename)) + + if rev is not None: + self.info("Updating to %s", rev) + os.system("(cd %s && hg up -C -r %s >&-)" % ( + filename, + rev, + )) + + return filename + def debug(self, msg, *args): log.debug(msg, *args) @@ -779,6 +832,11 @@ def open_with_auth(url): scheme, netloc, path, params, query, frag = urlparse.urlparse(url) + # Double scheme does not raise on Mac OS X as revealed by a + # failing test. We would expect "nonnumeric port". Refs #20. + if netloc.endswith(':'): + raise httplib.InvalidURL("nonnumeric port: ''") + if scheme in ('http', 'https'): auth, host = urllib2.splituser(netloc) else: @@ -859,4 +917,4 @@ def local_open(url): -# this line is a kludge to keep the trailing blank lines for pje's editor
\ No newline at end of file +# this line is a kludge to keep the trailing blank lines for pje's editor diff --git a/setuptools/tests/test_dist_info.py b/setuptools/tests/test_dist_info.py index 70dce2d4..fcb78c36 100644 --- a/setuptools/tests/test_dist_info.py +++ b/setuptools/tests/test_dist_info.py @@ -7,7 +7,7 @@ import unittest import textwrap try: - import _markerlib + import ast except: pass @@ -34,8 +34,8 @@ class TestDistInfo(unittest.TestCase): assert versioned.version == '2.718' # from filename assert unversioned.version == '0.3' # from METADATA - @skipIf('_markerlib' not in globals(), - "_markerlib is used to test conditional dependencies (Python >= 2.5)") + @skipIf('ast' not in globals(), + "ast is used to test conditional dependencies (Python >= 2.6)") def test_conditional_dependencies(self): requires = [pkg_resources.Requirement.parse('splort==4'), pkg_resources.Requirement.parse('quux>=1.1')] @@ -50,7 +50,8 @@ class TestDistInfo(unittest.TestCase): versioned = os.path.join(self.tmpdir, 'VersionedDistribution-2.718.dist-info') os.mkdir(versioned) - open(os.path.join(versioned, 'METADATA'), 'w+').write(DALS( + metadata_file = open(os.path.join(versioned, 'METADATA'), 'w+') + metadata_file.write(DALS( """ Metadata-Version: 1.2 Name: VersionedDistribution @@ -58,11 +59,13 @@ class TestDistInfo(unittest.TestCase): Provides-Extra: baz Requires-Dist: quux (>=1.1); extra == 'baz' """)) + metadata_file.close() unversioned = os.path.join(self.tmpdir, 'UnversionedDistribution.dist-info') os.mkdir(unversioned) - open(os.path.join(unversioned, 'METADATA'), 'w+').write(DALS( + metadata_file = open(os.path.join(unversioned, 'METADATA'), 'w+') + metadata_file.write(DALS( """ Metadata-Version: 1.2 Name: UnversionedDistribution @@ -71,6 +74,7 @@ class TestDistInfo(unittest.TestCase): Provides-Extra: baz Requires-Dist: quux (>=1.1); extra == 'baz' """)) + metadata_file.close() def tearDown(self): shutil.rmtree(self.tmpdir) diff --git a/setuptools/tests/test_markerlib.py b/setuptools/tests/test_markerlib.py index 4cce0430..7ff2f584 100644 --- a/setuptools/tests/test_markerlib.py +++ b/setuptools/tests/test_markerlib.py @@ -3,14 +3,14 @@ import unittest from setuptools.tests.py26compat import skipIf try: - import _ast + import ast except ImportError: pass class TestMarkerlib(unittest.TestCase): - @skipIf('_ast' not in globals(), - "ast not available (Python < 2.5?)") + @skipIf('ast' not in globals(), + "ast not available (Python < 2.6?)") def test_markers(self): from _markerlib import interpret, default_environment, compile @@ -62,37 +62,3 @@ class TestMarkerlib(unittest.TestCase): statement = "python_version == '5'" self.assertEqual(compile(statement).__doc__, statement) - @skipIf('_ast' not in globals(), - "ast not available (Python < 2.5?)") - def test_ast(self): - try: - import ast, nose - raise nose.SkipTest() - except ImportError: - pass - - # Nonsensical code coverage tests. - import _markerlib._markers_ast as _markers_ast - - class Node(_ast.AST): - _fields = ('bogus') - list(_markers_ast.iter_fields(Node())) - - class Node2(_ast.AST): - def __init__(self): - self._fields = ('bogus',) - self.bogus = [Node()] - - class NoneTransformer(_markers_ast.NodeTransformer): - def visit_Attribute(self, node): - return None - - def visit_Str(self, node): - return None - - def visit_Node(self, node): - return [] - - NoneTransformer().visit(_markers_ast.parse('a.b = "c"')) - NoneTransformer().visit(Node2()) - diff --git a/setuptools/tests/test_sdist.py b/setuptools/tests/test_sdist.py index 8d9ed922..a9d5d6e5 100644 --- a/setuptools/tests/test_sdist.py +++ b/setuptools/tests/test_sdist.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- """sdist tests""" @@ -6,10 +7,13 @@ import shutil import sys import tempfile import unittest +import urllib +import unicodedata from StringIO import StringIO from setuptools.command.sdist import sdist +from setuptools.command.egg_info import manifest_maker from setuptools.dist import Distribution @@ -28,7 +32,52 @@ 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, unicode): + 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') @@ -62,18 +111,273 @@ class TestSdistTest(unittest.TestCase): cmd.ensure_finalized() # squelch output - old_stdout = sys.stdout - old_stderr = sys.stderr - sys.stdout = StringIO() - sys.stderr = StringIO() + quiet() try: cmd.run() finally: - sys.stdout = old_stdout - sys.stderr = old_stderr + 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: + 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: + 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: + 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: + 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) + + 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,): + if sys.platform == 'win32': + # Python 3 mangles the UTF-8 filename + filename = filename.decode('cp1252') + 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() + + quiet() + try: + cmd.run() + finally: + unquiet() + + if sys.version_info >= (3,): + filename = filename.decode('latin-1') + if sys.platform == 'win32': + # Latin-1 is similar to Windows-1252 + self.assertTrue(filename in cmd.filelist.files) + else: + # The Latin-1 filename should have been skipped + 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) + + +def test_suite(): + return unittest.defaultTestLoader.loadTestsFromName(__name__) - self.assert_(os.path.join('sdist_test', 'a.txt') in manifest) - self.assert_(os.path.join('sdist_test', 'b.txt') in manifest) - self.assert_(os.path.join('sdist_test', 'c.rst') not in manifest) diff --git a/setuptools/tests/test_upload_docs.py b/setuptools/tests/test_upload_docs.py index 8b2dc892..769f16cc 100644 --- a/setuptools/tests/test_upload_docs.py +++ b/setuptools/tests/test_upload_docs.py @@ -54,12 +54,19 @@ class TestUploadDocsTest(unittest.TestCase): cmd = upload_docs(dist) cmd.upload_dir = self.upload_dir - zip_file = cmd.create_zipfile() + cmd.target_dir = self.upload_dir + tmp_dir = tempfile.mkdtemp() + tmp_file = os.path.join(tmp_dir, 'foo.zip') + try: + zip_file = cmd.create_zipfile(tmp_file) - assert zipfile.is_zipfile(zip_file) + assert zipfile.is_zipfile(tmp_file) - zip_f = zipfile.ZipFile(zip_file) # woh... + zip_file = zipfile.ZipFile(tmp_file) # woh... - assert zip_f.namelist() == ['index.html'] + assert zip_file.namelist() == ['index.html'] + zip_file.close() + finally: + shutil.rmtree(tmp_dir) |
