aboutsummaryrefslogtreecommitdiffstats
path: root/setuptools
diff options
context:
space:
mode:
authorJason R. Coombs <jaraco@jaraco.com>2013-06-18 14:08:20 -0500
committerJason R. Coombs <jaraco@jaraco.com>2013-06-18 14:08:20 -0500
commita85aa143f971ebfbb31ccaf58cb82a311f9315c6 (patch)
treeeeae1529ae15884aca3301fefae768fc2e531a18 /setuptools
parent94fc39cb62df19e85b07658f2fa5d0b4a7bf9303 (diff)
parent641eac6550896506fa939205f249bcfb8f057d57 (diff)
downloadexternal_python_setuptools-a85aa143f971ebfbb31ccaf58cb82a311f9315c6.tar.gz
external_python_setuptools-a85aa143f971ebfbb31ccaf58cb82a311f9315c6.tar.bz2
external_python_setuptools-a85aa143f971ebfbb31ccaf58cb82a311f9315c6.zip
Merge Vinay Sajip's unified Python 2/3 support from distribute 3
--HG-- branch : distribute
Diffstat (limited to 'setuptools')
-rwxr-xr-xsetuptools/archive_util.py3
-rw-r--r--setuptools/cli-32.exebin69632 -> 65536 bytes
-rw-r--r--setuptools/cli-64.exebin75264 -> 74752 bytes
-rw-r--r--setuptools/cli-arm-32.exebin0 -> 69120 bytes
-rw-r--r--setuptools/cli.exebin69632 -> 65536 bytes
-rwxr-xr-xsetuptools/command/develop.py4
-rwxr-xr-xsetuptools/command/easy_install.py64
-rwxr-xr-xsetuptools/command/egg_info.py46
-rw-r--r--setuptools/command/launcher manifest.xml15
-rwxr-xr-xsetuptools/command/sdist.py7
-rwxr-xr-xsetuptools/command/upload.py5
-rw-r--r--setuptools/command/upload_docs.py128
-rw-r--r--setuptools/dist.py5
-rw-r--r--setuptools/gui-32.exebin65536 -> 65536 bytes
-rw-r--r--setuptools/gui-64.exebin75264 -> 75264 bytes
-rw-r--r--setuptools/gui-arm-32.exebin0 -> 69120 bytes
-rw-r--r--setuptools/gui.exebin65536 -> 65536 bytes
-rwxr-xr-xsetuptools/package_index.py91
-rw-r--r--setuptools/py24compat.py11
-rwxr-xr-xsetuptools/sandbox.py5
-rw-r--r--setuptools/site-patch.py83
-rw-r--r--setuptools/tests/doctest.py8
-rw-r--r--setuptools/tests/test_develop.py12
-rw-r--r--setuptools/tests/test_dist_info.py12
-rw-r--r--setuptools/tests/test_easy_install.py4
-rw-r--r--setuptools/tests/test_markerlib.py18
-rw-r--r--setuptools/tests/test_resources.py30
-rw-r--r--setuptools/tests/test_sdist.py347
-rw-r--r--setuptools/tests/test_upload_docs.py15
-rw-r--r--setuptools/tests/win_script_wrapper.txt18
30 files changed, 726 insertions, 205 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/cli-32.exe b/setuptools/cli-32.exe
index 9b7717b7..b1487b78 100644
--- a/setuptools/cli-32.exe
+++ b/setuptools/cli-32.exe
Binary files differ
diff --git a/setuptools/cli-64.exe b/setuptools/cli-64.exe
index 265585af..675e6bf3 100644
--- a/setuptools/cli-64.exe
+++ b/setuptools/cli-64.exe
Binary files differ
diff --git a/setuptools/cli-arm-32.exe b/setuptools/cli-arm-32.exe
new file mode 100644
index 00000000..2f40402d
--- /dev/null
+++ b/setuptools/cli-arm-32.exe
Binary files differ
diff --git a/setuptools/cli.exe b/setuptools/cli.exe
index 9b7717b7..b1487b78 100644
--- a/setuptools/cli.exe
+++ b/setuptools/cli.exe
Binary files differ
diff --git a/setuptools/command/develop.py b/setuptools/command/develop.py
index 709e349c..1d500040 100755
--- a/setuptools/command/develop.py
+++ b/setuptools/command/develop.py
@@ -132,7 +132,9 @@ class develop(easy_install):
def uninstall_link(self):
if os.path.exists(self.egg_link):
log.info("Removing %s (link to %s)", self.egg_link, self.egg_base)
- contents = [line.rstrip() for line in open(self.egg_link)]
+ egg_link_file = open(self.egg_link)
+ contents = [line.rstrip() for line in egg_link_file]
+ egg_link_file.close()
if contents not in ([self.egg_path], [self.egg_path, self.setup_path]):
log.warn("Link points to %s: uninstall aborted", contents)
return
diff --git a/setuptools/command/easy_install.py b/setuptools/command/easy_install.py
index 8ce71614..50339e8f 100755
--- a/setuptools/command/easy_install.py
+++ b/setuptools/command/easy_install.py
@@ -19,7 +19,9 @@ import zipfile
import re
import stat
import random
+import platform
from glob import glob
+import pkg_resources
from setuptools import Command, _dont_write_bytecode
from setuptools.sandbox import run_setup
from distutils import log, dir_util
@@ -493,7 +495,7 @@ Please make the appropriate changes for your system and try again.
self.cant_write_to_target()
else:
try:
- f.write("import os;open(%r,'w').write('OK')\n" % (ok_file,))
+ f.write("import os; f = open(%r, 'w'); f.write('OK'); f.close()\n" % (ok_file,))
f.close(); f=None
executable = sys.executable
if os.name=='nt':
@@ -524,6 +526,10 @@ Please make the appropriate changes for your system and try again.
"""Write all the scripts for `dist`, unless scripts are excluded"""
if not self.exclude_scripts and dist.metadata_isdir('scripts'):
for script_name in dist.metadata_listdir('scripts'):
+ if dist.metadata_isdir('scripts/' + script_name):
+ # The "script" is a directory, likely a Python 3
+ # __pycache__ directory, so skip it.
+ continue
self.install_script(
dist, script_name,
dist.get_metadata('scripts/'+script_name)
@@ -1276,7 +1282,7 @@ Please make the appropriate changes for your system and try again.""" % (
return # already did it, or don't need to
sitepy = os.path.join(self.install_dir, "site.py")
- source = resource_string(Requirement.parse("distribute"), "site.py")
+ source = resource_string("setuptools", "site-patch.py")
current = ""
if os.path.exists(sitepy):
@@ -1529,7 +1535,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)), ''))
@@ -1794,6 +1803,11 @@ def chmod(path, mode):
def fix_jython_executable(executable, options):
if sys.platform.startswith('java') and is_sh(executable):
+ # Workaround for Jython is not needed on Linux systems.
+ import java
+ if java.lang.System.getProperty("os.name") == "Linux":
+ return executable
+
# Workaround Jython's sys.executable being a .sh (an invalid
# shebang line interpreter)
if options:
@@ -1828,31 +1842,61 @@ def get_script_args(dist, executable=sys_executable, wininst=False):
if sys.platform=='win32' or wininst:
# On Windows/wininst, add a .py extension and an .exe launcher
if group=='gui_scripts':
- ext, launcher = '-script.pyw', 'gui.exe'
+ launcher_type = 'gui'
+ ext = '-script.pyw'
old = ['.pyw']
new_header = re.sub('(?i)python.exe','pythonw.exe',header)
else:
- ext, launcher = '-script.py', 'cli.exe'
+ launcher_type = 'cli'
+ ext = '-script.py'
old = ['.py','.pyc','.pyo']
new_header = re.sub('(?i)pythonw.exe','python.exe',header)
- if is_64bit():
- launcher = launcher.replace(".", "-64.")
- else:
- launcher = launcher.replace(".", "-32.")
if os.path.exists(new_header[2:-1]) or sys.platform!='win32':
hdr = new_header
else:
hdr = header
yield (name+ext, hdr+script_text, 't', [name+x for x in old])
yield (
- name+'.exe', resource_string('setuptools', launcher),
+ name+'.exe', get_win_launcher(launcher_type),
'b' # write in binary mode
)
+ if not is_64bit():
+ # install a manifest for the launcher to prevent Windows
+ # from detecting it as an installer (which it will for
+ # launchers like easy_install.exe). Consider only
+ # adding a manifest for launchers detected as installers.
+ # See Distribute #143 for details.
+ m_name = name + '.exe.manifest'
+ yield (m_name, load_launcher_manifest(name), 't')
else:
# On other platforms, we assume the right thing to do is to
# just write the stub with no extension.
yield (name, header+script_text)
+def get_win_launcher(type):
+ """
+ Load the Windows launcher (executable) suitable for launching a script.
+
+ `type` should be either 'cli' or 'gui'
+
+ Returns the executable as a byte string.
+ """
+ launcher_fn = '%s.exe' % type
+ if platform.machine().lower()=='arm':
+ launcher_fn = launcher_fn.replace(".", "-arm.")
+ if is_64bit():
+ launcher_fn = launcher_fn.replace(".", "-64.")
+ else:
+ launcher_fn = launcher_fn.replace(".", "-32.")
+ return resource_string('setuptools', launcher_fn)
+
+def load_launcher_manifest(name):
+ manifest = pkg_resources.resource_string(__name__, 'launcher manifest.xml')
+ if sys.version_info[0] < 3:
+ return manifest % vars()
+ else:
+ return manifest.decode('utf-8') % vars()
+
def rmtree(path, ignore_errors=False, onerror=auto_chmod):
"""Recursively delete a directory tree.
diff --git a/setuptools/command/egg_info.py b/setuptools/command/egg_info.py
index 124c410e..12acc422 100755
--- a/setuptools/command/egg_info.py
+++ b/setuptools/command/egg_info.py
@@ -10,7 +10,7 @@ from distutils import log
from setuptools.command.sdist import sdist
from setuptools.compat import basestring
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 setuptools.command.sdist import walk_revctrl
@@ -275,35 +275,34 @@ 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)
-def compose(path):
- # Apple's HFS Plus returns decomposed UTF-8. Since just about
- # everyone else chokes on it, we must make sure to return fully
- # composed UTF-8 only.
- if sys.getfilesystemencoding().lower() == 'utf-8':
- from unicodedata import normalize
- if sys.version_info >= (3,):
- path = normalize('NFC', path)
- else:
- path = normalize('NFC', path.decode('utf-8')).encode('utf-8')
- return path
class manifest_maker(sdist):
@@ -330,7 +329,6 @@ class manifest_maker(sdist):
self.prune_file_list()
self.filelist.sort()
self.filelist.remove_duplicates()
- self.filelist.files = [compose(path) for path in self.filelist.files]
self.write_manifest()
def write_manifest (self):
@@ -338,6 +336,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/launcher manifest.xml b/setuptools/command/launcher manifest.xml
new file mode 100644
index 00000000..844d2264
--- /dev/null
+++ b/setuptools/command/launcher manifest.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+<assemblyIdentity version="1.0.0.0"
+ processorArchitecture="X86"
+ name="%(name)s"
+ type="win32"/>
+ <!-- Identify the application security requirements. -->
+ <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
+ <security>
+ <requestedPrivileges>
+ <requestedExecutionLevel level="asInvoker" uiAccess="false"/>
+ </requestedPrivileges>
+ </security>
+ </trustInfo>
+</assembly>
diff --git a/setuptools/command/sdist.py b/setuptools/command/sdist.py
index 56ef8a66..6f3f48c8 100755
--- a/setuptools/command/sdist.py
+++ b/setuptools/command/sdist.py
@@ -282,8 +282,13 @@ class sdist(_sdist):
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,):
- line = line.decode('UTF-8')
+ 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:
diff --git a/setuptools/command/upload.py b/setuptools/command/upload.py
index bf9c0668..7edbf56a 100755
--- a/setuptools/command/upload.py
+++ b/setuptools/command/upload.py
@@ -108,8 +108,9 @@ class upload(Command):
data['comment'] = comment
if self.sign:
- data['gpg_signature'] = (os.path.basename(filename) + ".asc",
- open(filename+".asc").read())
+ asc_file = open(filename + ".asc")
+ data['gpg_signature'] = (os.path.basename(filename) + ".asc", asc_file.read())
+ asc_file.close()
# set up the authentication
auth = "Basic " + base64.encodestring(self.username + ":" + self.password).strip()
diff --git a/setuptools/command/upload_docs.py b/setuptools/command/upload_docs.py
index 505ddadb..178a8793 100644
--- a/setuptools/command/upload_docs.py
+++ b/setuptools/command/upload_docs.py
@@ -8,9 +8,12 @@ PyPI's packages.python.org).
import os
import socket
import zipfile
-import base64
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
@@ -24,18 +27,12 @@ from setuptools.compat import httplib, urlparse
_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,43 +48,67 @@ 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()
+ f = open(filename, 'rb')
+ content = f.read()
+ f.close()
meta = self.distribution.metadata
data = {
':action': 'doc_upload',
@@ -95,36 +116,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 d90acbec..62dd0eb2 100644
--- a/setuptools/dist.py
+++ b/setuptools/dist.py
@@ -660,6 +660,11 @@ class Distribution(_Distribution):
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
diff --git a/setuptools/gui-32.exe b/setuptools/gui-32.exe
index 3f64af7d..f8d35096 100644
--- a/setuptools/gui-32.exe
+++ b/setuptools/gui-32.exe
Binary files differ
diff --git a/setuptools/gui-64.exe b/setuptools/gui-64.exe
index 3ab4378e..330c51a5 100644
--- a/setuptools/gui-64.exe
+++ b/setuptools/gui-64.exe
Binary files differ
diff --git a/setuptools/gui-arm-32.exe b/setuptools/gui-arm-32.exe
new file mode 100644
index 00000000..537aff37
--- /dev/null
+++ b/setuptools/gui-arm-32.exe
Binary files differ
diff --git a/setuptools/gui.exe b/setuptools/gui.exe
index 3f64af7d..f8d35096 100644
--- a/setuptools/gui.exe
+++ b/setuptools/gui.exe
Binary files differ
diff --git a/setuptools/package_index.py b/setuptools/package_index.py
index 2cab63c1..85a1deeb 100755
--- a/setuptools/package_index.py
+++ b/setuptools/package_index.py
@@ -1,5 +1,6 @@
"""PyPI and direct package downloading"""
import sys, os.path, re, shutil, random, socket
+import itertools
import base64
from pkg_resources import *
from distutils import log
@@ -14,6 +15,8 @@ except ImportError:
from md5 import md5
from fnmatch import translate
+from setuptools.py24compat import wraps
+
EGG_FRAGMENT = re.compile(r'^egg=([-A-Za-z0-9_.]+)$')
HREF = re.compile("""href\\s*=\\s*['"]?([^'"> ]+)""", re.I)
# this is here to fix emacs' cruddy broken syntax highlighting
@@ -137,9 +140,38 @@ def interpret_distro_name(location, basename, metadata,
platform = platform
)
+# From Python 2.7 docs
+def unique_everseen(iterable, key=None):
+ "List unique elements, preserving order. Remember all elements ever seen."
+ # unique_everseen('AAAABBBCCDAABBB') --> A B C D
+ # unique_everseen('ABBCcAD', str.lower) --> A B C D
+ seen = set()
+ seen_add = seen.add
+ if key is None:
+ for element in itertools.ifilterfalse(seen.__contains__, iterable):
+ seen_add(element)
+ yield element
+ else:
+ for element in iterable:
+ k = key(element)
+ if k not in seen:
+ seen_add(k)
+ yield element
+
+def unique_values(func):
+ """
+ Wrap a function returning an iterable such that the resulting iterable
+ only ever yields unique items.
+ """
+ @wraps(func)
+ def wrapper(*args, **kwargs):
+ return unique_everseen(func(*args, **kwargs))
+ return wrapper
+
REL = re.compile("""<([^>]*\srel\s*=\s*['"]?([^'">]+)[^>]*)>""", re.I)
# this line is here to fix emacs' cruddy broken syntax highlighting
+@unique_values
def find_external_links(url, page):
"""Find rel="homepage" and rel="download" links in `page`, yielding URLs"""
@@ -157,6 +189,7 @@ def find_external_links(url, page):
if match:
yield urljoin(url, htmldecode(match.group(1)))
+
user_agent = "Python-urllib/%s distribute/%s" % (
sys.version[:3], require('distribute')[0].version
)
@@ -666,6 +699,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 url2pathname(urlparse.urlparse(url)[2])
else:
@@ -706,6 +743,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)
@@ -789,9 +875,8 @@ def open_with_auth(url):
# Double scheme does not raise on Mac OS X as revealed by a
# failing test. We would expect "nonnumeric port". Refs #20.
- if sys.platform == 'darwin':
- if netloc.endswith(':'):
- raise httplib.InvalidURL("nonnumeric port: ''")
+ if netloc.endswith(':'):
+ raise httplib.InvalidURL("nonnumeric port: ''")
if scheme in ('http', 'https'):
auth, host = splituser(netloc)
diff --git a/setuptools/py24compat.py b/setuptools/py24compat.py
new file mode 100644
index 00000000..c5d7d204
--- /dev/null
+++ b/setuptools/py24compat.py
@@ -0,0 +1,11 @@
+"""
+Forward-compatibility support for Python 2.4 and earlier
+"""
+
+# from jaraco.compat 1.2
+try:
+ from functools import wraps
+except ImportError:
+ def wraps(func):
+ "Just return the function unwrapped"
+ return lambda x: x
diff --git a/setuptools/sandbox.py b/setuptools/sandbox.py
index c49d1cfe..05b73d84 100755
--- a/setuptools/sandbox.py
+++ b/setuptools/sandbox.py
@@ -1,5 +1,8 @@
import os, sys, tempfile, operator, pkg_resources
-_os = sys.modules[os.name]
+if os.name == "java":
+ import org.python.modules.posix.PosixModule as _os
+else:
+ _os = sys.modules[os.name]
try:
_file = file
except NameError:
diff --git a/setuptools/site-patch.py b/setuptools/site-patch.py
new file mode 100644
index 00000000..a7166f14
--- /dev/null
+++ b/setuptools/site-patch.py
@@ -0,0 +1,83 @@
+def __boot():
+ import sys, os, os.path
+ PYTHONPATH = os.environ.get('PYTHONPATH')
+ if PYTHONPATH is None or (sys.platform=='win32' and not PYTHONPATH):
+ PYTHONPATH = []
+ else:
+ PYTHONPATH = PYTHONPATH.split(os.pathsep)
+
+ pic = getattr(sys,'path_importer_cache',{})
+ stdpath = sys.path[len(PYTHONPATH):]
+ mydir = os.path.dirname(__file__)
+ #print "searching",stdpath,sys.path
+
+ for item in stdpath:
+ if item==mydir or not item:
+ continue # skip if current dir. on Windows, or my own directory
+ importer = pic.get(item)
+ if importer is not None:
+ loader = importer.find_module('site')
+ if loader is not None:
+ # This should actually reload the current module
+ loader.load_module('site')
+ break
+ else:
+ try:
+ import imp # Avoid import loop in Python >= 3.3
+ stream, path, descr = imp.find_module('site',[item])
+ except ImportError:
+ continue
+ if stream is None:
+ continue
+ try:
+ # This should actually reload the current module
+ imp.load_module('site',stream,path,descr)
+ finally:
+ stream.close()
+ break
+ else:
+ raise ImportError("Couldn't find the real 'site' module")
+
+ #print "loaded", __file__
+
+ known_paths = dict([(makepath(item)[1],1) for item in sys.path]) # 2.2 comp
+
+ oldpos = getattr(sys,'__egginsert',0) # save old insertion position
+ sys.__egginsert = 0 # and reset the current one
+
+ for item in PYTHONPATH:
+ addsitedir(item)
+
+ sys.__egginsert += oldpos # restore effective old position
+
+ d,nd = makepath(stdpath[0])
+ insert_at = None
+ new_path = []
+
+ for item in sys.path:
+ p,np = makepath(item)
+
+ if np==nd and insert_at is None:
+ # We've hit the first 'system' path entry, so added entries go here
+ insert_at = len(new_path)
+
+ if np in known_paths or insert_at is None:
+ new_path.append(item)
+ else:
+ # new path after the insert point, back-insert it
+ new_path.insert(insert_at, item)
+ insert_at += 1
+
+ sys.path[:] = new_path
+
+if __name__=='site':
+ __boot()
+ del __boot
+
+
+
+
+
+
+
+
diff --git a/setuptools/tests/doctest.py b/setuptools/tests/doctest.py
index 1f23fd8e..35d588d0 100644
--- a/setuptools/tests/doctest.py
+++ b/setuptools/tests/doctest.py
@@ -1968,7 +1968,9 @@ def testfile(filename, module_relative=True, name=None, package=None,
runner = DocTestRunner(verbose=verbose, optionflags=optionflags)
# Read the file, convert it to a test, and run it.
- s = open(filename).read()
+ f = open(filename)
+ s = f.read()
+ f.close()
test = parser.get_doctest(s, globs, name, filename, 0)
runner.run(test)
@@ -2353,7 +2355,9 @@ def DocFileTest(path, module_relative=True, package=None,
# Find the file and read it.
name = os.path.basename(path)
- doc = open(path).read()
+ f = open(path)
+ doc = f.read()
+ f.close()
# Convert it to a test, and wrap it in a DocFileCase.
test = parser.get_doctest(doc, globs, name, path, 0)
diff --git a/setuptools/tests/test_develop.py b/setuptools/tests/test_develop.py
index 0813959d..9d7ce711 100644
--- a/setuptools/tests/test_develop.py
+++ b/setuptools/tests/test_develop.py
@@ -89,16 +89,16 @@ class TestDevelopTest(unittest.TestCase):
self.assertEqual(content, ['easy-install.pth', 'foo.egg-link'])
# Check that we are using the right code.
- f = open(os.path.join(site.USER_SITE, 'foo.egg-link'), 'rt')
+ egg_link_file = open(os.path.join(site.USER_SITE, 'foo.egg-link'), 'rt')
try:
- path = f.read().split()[0].strip()
+ path = egg_link_file.read().split()[0].strip()
finally:
- f.close()
- f = open(os.path.join(path, 'foo', '__init__.py'), 'rt')
+ egg_link_file.close()
+ init_file = open(os.path.join(path, 'foo', '__init__.py'), 'rt')
try:
- init = f.read().strip()
+ init = init_file.read().strip()
finally:
- f.close()
+ init_file.close()
if sys.version < "3":
self.assertEqual(init, 'print "foo"')
else:
diff --git a/setuptools/tests/test_dist_info.py b/setuptools/tests/test_dist_info.py
index 93ab8816..a8adb68c 100644
--- a/setuptools/tests/test_dist_info.py
+++ b/setuptools/tests/test_dist_info.py
@@ -50,9 +50,9 @@ class TestDistInfo(unittest.TestCase):
versioned = os.path.join(self.tmpdir,
'VersionedDistribution-2.718.dist-info')
os.mkdir(versioned)
- f = open(os.path.join(versioned, 'METADATA'), 'w+')
+ metadata_file = open(os.path.join(versioned, 'METADATA'), 'w+')
try:
- f.write(DALS(
+ metadata_file.write(DALS(
"""
Metadata-Version: 1.2
Name: VersionedDistribution
@@ -61,13 +61,13 @@ class TestDistInfo(unittest.TestCase):
Requires-Dist: quux (>=1.1); extra == 'baz'
"""))
finally:
- f.close()
+ metadata_file.close()
unversioned = os.path.join(self.tmpdir,
'UnversionedDistribution.dist-info')
os.mkdir(unversioned)
- f = open(os.path.join(unversioned, 'METADATA'), 'w+')
+ metadata_file = open(os.path.join(unversioned, 'METADATA'), 'w+')
try:
- f.write(DALS(
+ metadata_file.write(DALS(
"""
Metadata-Version: 1.2
Name: UnversionedDistribution
@@ -77,7 +77,7 @@ class TestDistInfo(unittest.TestCase):
Requires-Dist: quux (>=1.1); extra == 'baz'
"""))
finally:
- f.close()
+ metadata_file.close()
def tearDown(self):
shutil.rmtree(self.tmpdir)
diff --git a/setuptools/tests/test_easy_install.py b/setuptools/tests/test_easy_install.py
index 34faeaad..d76025d2 100644
--- a/setuptools/tests/test_easy_install.py
+++ b/setuptools/tests/test_easy_install.py
@@ -13,7 +13,7 @@ import tarfile
import distutils.core
from setuptools.sandbox import run_setup, SandboxViolation
-from setuptools.command.easy_install import easy_install, get_script_args, main
+from setuptools.command.easy_install import easy_install, fix_jython_executable, get_script_args, main
from setuptools.command.easy_install import PthDistributions
from setuptools.command import easy_install as easy_install_pkg
from setuptools.dist import Distribution
@@ -51,7 +51,7 @@ if __name__ == '__main__':
sys.exit(
load_entry_point('spec', 'console_scripts', 'name')()
)
-""" % sys.executable
+""" % fix_jython_executable(sys.executable, "")
SETUP_PY = """\
from setuptools import setup
diff --git a/setuptools/tests/test_markerlib.py b/setuptools/tests/test_markerlib.py
index 7ff2f584..aa461846 100644
--- a/setuptools/tests/test_markerlib.py
+++ b/setuptools/tests/test_markerlib.py
@@ -16,15 +16,15 @@ class TestMarkerlib(unittest.TestCase):
os_name = os.name
- self.assert_(interpret(""))
+ self.assertTrue(interpret(""))
- self.assert_(interpret("os.name != 'buuuu'"))
- self.assert_(interpret("python_version > '1.0'"))
- self.assert_(interpret("python_version < '5.0'"))
- self.assert_(interpret("python_version <= '5.0'"))
- self.assert_(interpret("python_version >= '1.0'"))
- self.assert_(interpret("'%s' in os.name" % os_name))
- self.assert_(interpret("'buuuu' not in os.name"))
+ self.assertTrue(interpret("os.name != 'buuuu'"))
+ self.assertTrue(interpret("python_version > '1.0'"))
+ self.assertTrue(interpret("python_version < '5.0'"))
+ self.assertTrue(interpret("python_version <= '5.0'"))
+ self.assertTrue(interpret("python_version >= '1.0'"))
+ self.assertTrue(interpret("'%s' in os.name" % os_name))
+ self.assertTrue(interpret("'buuuu' not in os.name"))
self.assertFalse(interpret("os.name == 'buuuu'"))
self.assertFalse(interpret("python_version < '1.0'"))
@@ -36,7 +36,7 @@ class TestMarkerlib(unittest.TestCase):
environment = default_environment()
environment['extra'] = 'test'
- self.assert_(interpret("extra == 'test'", environment))
+ self.assertTrue(interpret("extra == 'test'", environment))
self.assertFalse(interpret("extra == 'doc'", environment))
def raises_nameError():
diff --git a/setuptools/tests/test_resources.py b/setuptools/tests/test_resources.py
index 4b3d50a8..a2ec03c0 100644
--- a/setuptools/tests/test_resources.py
+++ b/setuptools/tests/test_resources.py
@@ -478,13 +478,14 @@ class ParseTests(TestCase):
p1, p2 = parse_version(s1),parse_version(s2)
self.assertEqual(p1,p2, (s1,s2,p1,p2))
+ c('1.2-rc1', '1.2rc1')
c('0.4', '0.4.0')
c('0.4.0.0', '0.4.0')
c('0.4.0-0', '0.4-0')
c('0pl1', '0.0pl1')
c('0pre1', '0.0c1')
c('0.0.0preview1', '0c1')
- c('0.0c1', '0rc1')
+ c('0.0c1', '0-rc1')
c('1.2a1', '1.2.a.1'); c('1.2...a', '1.2a')
def testVersionOrdering(self):
@@ -493,14 +494,11 @@ class ParseTests(TestCase):
self.assertTrue(p1<p2, (s1,s2,p1,p2))
c('2.1','2.1.1')
- c('2.1.0','2.10')
c('2a1','2b0')
- c('2b1','2c0')
c('2a1','2.1')
c('2.3a1', '2.3')
c('2.1-1', '2.1-2')
c('2.1-1', '2.1.1')
- c('2.1', '2.1.1-1')
c('2.1', '2.1pl4')
c('2.1a0-20040501', '2.1')
c('1.1', '02.1')
@@ -511,20 +509,8 @@ class ParseTests(TestCase):
c('0.4', '4.0')
c('0.0.4', '0.4.0')
c('0pl1', '0.4pl1')
+ c('2.1.0-rc1','2.1.0')
c('2.1dev','2.1a0')
- c('2.1.0rc1','2.1.0')
- c('2.1.0','2.1.0-rc0')
- c('2.1.0','2.1.0-a')
- c('2.1.0','2.1.0-alpha')
- c('2.1.0','2.1.0-foo')
- c('1.0','1.0-1')
- c('1.0-1','1.0.1')
- c('1.0a','1.0b')
- c('1.0dev','1.0rc1')
- c('1.0pre','1.0')
- c('1.0pre','1.0')
- c('1.0a','1.0-a')
- c('1.0rc1','1.0-rc1')
torture ="""
0.80.1-3 0.80.1-2 0.80.1-1 0.79.9999+0.80.0pre4-1
@@ -562,6 +548,15 @@ class ScriptHeaderTests(TestCase):
if (sys.version_info >= (3,) and os.environ.get("LC_CTYPE")
in (None, "C", "POSIX")):
return
+
+ class java:
+ class lang:
+ class System:
+ @staticmethod
+ def getProperty(property):
+ return ""
+ sys.modules["java"] = java
+
platform = sys.platform
sys.platform = 'java1.5.0_13'
stdout = sys.stdout
@@ -585,6 +580,7 @@ class ScriptHeaderTests(TestCase):
'#!%s -x\n' % self.non_ascii_exe)
self.assertTrue('Unable to adapt shebang line' in sys.stdout.getvalue())
finally:
+ del sys.modules["java"]
sys.platform = platform
sys.stdout = stdout
diff --git a/setuptools/tests/test_sdist.py b/setuptools/tests/test_sdist.py
index 49007c3d..ececa765 100644
--- a/setuptools/tests/test_sdist.py
+++ b/setuptools/tests/test_sdist.py
@@ -7,9 +7,11 @@ import shutil
import sys
import tempfile
import unittest
+import unicodedata
-from setuptools.compat import StringIO
+from setuptools.compat import StringIO, urllib
from setuptools.command.sdist import sdist
+from setuptools.command.egg_info import manifest_maker
from setuptools.dist import Distribution
@@ -28,7 +30,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,106 +109,286 @@ 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_filelist_is_fully_composed(self):
- # Test for #303. Requires HFS Plus to fail.
-
- # Add file with non-ASCII filename
- filename = os.path.join('sdist_test', 'smörbröd.py')
- open(filename, 'w').close()
-
+ def test_manifest_is_written_with_utf8_encoding(self):
+ # Test for #303.
dist = Distribution(SETUP_ATTRS)
dist.script_name = 'setup.py'
- cmd = sdist(dist)
- cmd.ensure_finalized()
+ mm = manifest_maker(dist)
+ mm.manifest = os.path.join('sdist_test.egg-info', 'SOURCES.txt')
+ os.mkdir('sdist_test.egg-info')
- # squelch output
- old_stdout = sys.stdout
- old_stderr = sys.stderr
- sys.stdout = StringIO()
- sys.stderr = StringIO()
+ # UTF-8 filename
+ filename = os.path.join('sdist_test', 'smörbröd.py')
+
+ # Add UTF-8 filename and write manifest
+ quiet()
try:
- cmd.run()
+ mm.run()
+ mm.filelist.files.append(filename)
+ mm.write_manifest()
finally:
- sys.stdout = old_stdout
- sys.stderr = old_stderr
+ unquiet()
- self.assertTrue(filename in cmd.filelist.files)
+ manifest = open(mm.manifest, 'rbU')
+ contents = manifest.read()
+ manifest.close()
- def test_manifest_is_written_in_utf8(self):
+ # 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.
-
- # Add file with non-ASCII filename
- filename = os.path.join('sdist_test', 'smörbröd.py')
- open(filename, 'w').close()
-
dist = Distribution(SETUP_ATTRS)
dist.script_name = 'setup.py'
cmd = sdist(dist)
cmd.ensure_finalized()
- # squelch output
- old_stdout = sys.stdout
- old_stderr = sys.stderr
- sys.stdout = StringIO()
- sys.stderr = StringIO()
+ # Create manifest
+ quiet()
try:
cmd.run()
finally:
- sys.stdout = old_stdout
- sys.stderr = old_stderr
+ unquiet()
- manifest = open(os.path.join('sdist_test.egg-info', 'SOURCES.txt'), 'rbU')
- contents = manifest.read()
+ # 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()
- self.assertTrue(len(contents))
- # This must not fail:
- contents.decode('UTF-8')
+ # The file must exist to be included in the filelist
+ open(filename, 'w').close()
- def test_manifest_is_read_in_utf8(self):
- # Test for #303.
+ # Re-read manifest
+ cmd.filelist.files = []
+ quiet()
+ try:
+ cmd.read_manifest()
+ finally:
+ unquiet()
- # Add file with non-ASCII filename
- filename = os.path.join('sdist_test', 'smörbröd.py')
- open(filename, 'w').close()
+ # 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()
- # squelch output
- old_stdout = sys.stdout
- old_stderr = sys.stderr
- sys.stdout = StringIO()
- sys.stderr = StringIO()
+ # UTF-8 filename
+ filename = os.path.join(b('sdist_test'), b('smörbröd.py'))
+ open(filename, 'w').close()
+
+ quiet()
try:
cmd.run()
finally:
- sys.stdout = old_stdout
- sys.stderr = old_stderr
+ 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()
- cmd.filelist.files = []
- cmd.manifest = os.path.join('sdist_test.egg-info', 'SOURCES.txt')
- cmd.read_manifest()
+ # Latin-1 filename
+ filename = os.path.join(b('sdist_test'), LATIN1_FILENAME)
+ open(filename, 'w').close()
+ self.assertTrue(os.path.isfile(filename))
- self.assertTrue(filename in cmd.filelist.files)
+ 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)
def test_suite():
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)
diff --git a/setuptools/tests/win_script_wrapper.txt b/setuptools/tests/win_script_wrapper.txt
index 1fe47bc5..731243dd 100644
--- a/setuptools/tests/win_script_wrapper.txt
+++ b/setuptools/tests/win_script_wrapper.txt
@@ -17,7 +17,7 @@ Let's create a simple script, foo-script.py:
>>> from setuptools.command.easy_install import nt_quote_arg
>>> sample_directory = tempfile.mkdtemp()
>>> f = open(os.path.join(sample_directory, 'foo-script.py'), 'w')
- >>> bytes = f.write(
+ >>> bytes_written = f.write(
... """#!%(python_exe)s
... import sys
... input = repr(sys.stdin.read())
@@ -37,8 +37,8 @@ We'll also copy cli.exe to the sample-directory with the name foo.exe:
>>> import pkg_resources
>>> f = open(os.path.join(sample_directory, 'foo.exe'), 'wb')
- >>> bytes = f.write(
- ... pkg_resources.resource_string('setuptools', 'cli.exe')
+ >>> bytes_written = f.write(
+ ... pkg_resources.resource_string('setuptools', 'cli-32.exe')
... )
>>> f.close()
@@ -82,7 +82,7 @@ options as usual. For example, to run in optimized mode and
enter the interpreter after running the script, you could use -Oi:
>>> f = open(os.path.join(sample_directory, 'foo-script.py'), 'w')
- >>> bytes = f.write(
+ >>> bytes_written = f.write(
... """#!%(python_exe)s -Oi
... import sys
... input = repr(sys.stdin.read())
@@ -112,10 +112,12 @@ Now let's test the GUI version with the simple scipt, bar-script.py:
>>> from setuptools.command.easy_install import nt_quote_arg
>>> sample_directory = tempfile.mkdtemp()
>>> f = open(os.path.join(sample_directory, 'bar-script.pyw'), 'w')
- >>> bytes = f.write(
+ >>> bytes_written = f.write(
... """#!%(python_exe)s
... import sys
- ... open(sys.argv[1], 'wb').write(repr(sys.argv[2]).encode('ascii'))
+ ... f = open(sys.argv[1], 'wb')
+ ... bytes_written = f.write(repr(sys.argv[2]).encode('utf-8'))
+ ... f.close()
... """ % dict(python_exe=nt_quote_arg(sys.executable)))
>>> f.close()
@@ -123,8 +125,8 @@ We'll also copy gui.exe to the sample-directory with the name bar.exe:
>>> import pkg_resources
>>> f = open(os.path.join(sample_directory, 'bar.exe'), 'wb')
- >>> bytes = f.write(
- ... pkg_resources.resource_string('setuptools', 'gui.exe')
+ >>> bytes_written = f.write(
+ ... pkg_resources.resource_string('setuptools', 'gui-32.exe')
... )
>>> f.close()