summaryrefslogtreecommitdiff
path: root/setuptools
diff options
context:
space:
mode:
authorJason R. Coombs <jaraco@jaraco.com>2014-09-29 21:14:51 -0400
committerJason R. Coombs <jaraco@jaraco.com>2014-09-29 21:14:51 -0400
commit459fa2041143a2ee9a221b21191d5dfc5d444ebd (patch)
tree10a62f8bca69d5b035079d764e494f50701eee15 /setuptools
parent2d6594b74de045821a7dbb4dd88b46a51af312e4 (diff)
parentfad1cf2b4cec5fc9b48608ef4c34c2713842e2e0 (diff)
downloadpython-setuptools-bitbucket-459fa2041143a2ee9a221b21191d5dfc5d444ebd.tar.gz
Merge with 6.0.2
Diffstat (limited to 'setuptools')
-rwxr-xr-xsetuptools/command/egg_info.py2
-rw-r--r--setuptools/command/install_lib.py83
-rwxr-xr-xsetuptools/command/sdist.py8
-rw-r--r--setuptools/dist.py2
-rw-r--r--setuptools/extension.py6
-rw-r--r--setuptools/msvc9_support.py64
-rwxr-xr-xsetuptools/sandbox.py7
-rw-r--r--setuptools/ssl_support.py9
-rw-r--r--setuptools/svn_utils.py2
-rw-r--r--setuptools/tests/test_integration.py3
-rw-r--r--setuptools/tests/test_msvc9compiler.py157
-rw-r--r--setuptools/tests/test_resources.py27
-rw-r--r--setuptools/tests/test_sandbox.py10
-rw-r--r--setuptools/tests/test_sdist.py28
-rw-r--r--setuptools/tests/win_script_wrapper.txt8
-rw-r--r--setuptools/utils.py11
-rw-r--r--setuptools/version.py2
17 files changed, 381 insertions, 48 deletions
diff --git a/setuptools/command/egg_info.py b/setuptools/command/egg_info.py
index debb52e4..14ff0763 100755
--- a/setuptools/command/egg_info.py
+++ b/setuptools/command/egg_info.py
@@ -390,7 +390,7 @@ def write_toplevel_names(cmd, basename, filename):
for k in cmd.distribution.iter_distribution_names()
]
)
- cmd.write_file("top-level names", filename, '\n'.join(pkgs) + '\n')
+ cmd.write_file("top-level names", filename, '\n'.join(sorted(pkgs)) + '\n')
def overwrite_arg(cmd, basename, filename):
diff --git a/setuptools/command/install_lib.py b/setuptools/command/install_lib.py
index d7e117f0..9b772227 100644
--- a/setuptools/command/install_lib.py
+++ b/setuptools/command/install_lib.py
@@ -1,6 +1,7 @@
-import distutils.command.install_lib as orig
import os
-
+import imp
+from itertools import product, starmap
+import distutils.command.install_lib as orig
class install_lib(orig.install_lib):
"""Don't add compiled flags to filenames of non-Python files"""
@@ -13,19 +14,71 @@ class install_lib(orig.install_lib):
self.byte_compile(outfiles)
def get_exclusions(self):
- exclude = {}
- nsp = self.distribution.namespace_packages
- svem = (nsp and self.get_finalized_command('install')
- .single_version_externally_managed)
- if svem:
- for pkg in nsp:
- parts = pkg.split('.')
- while parts:
- pkgdir = os.path.join(self.install_dir, *parts)
- for f in '__init__.py', '__init__.pyc', '__init__.pyo':
- exclude[os.path.join(pkgdir, f)] = 1
- parts.pop()
- return exclude
+ """
+ Return a collections.Sized collections.Container of paths to be
+ excluded for single_version_externally_managed installations.
+ """
+ all_packages = (
+ pkg
+ for ns_pkg in self._get_SVEM_NSPs()
+ for pkg in self._all_packages(ns_pkg)
+ )
+
+ excl_specs = product(all_packages, self._gen_exclusion_paths())
+ return set(starmap(self._exclude_pkg_path, excl_specs))
+
+ def _exclude_pkg_path(self, pkg, exclusion_path):
+ """
+ Given a package name and exclusion path within that package,
+ compute the full exclusion path.
+ """
+ parts = pkg.split('.') + [exclusion_path]
+ return os.path.join(self.install_dir, *parts)
+
+ @staticmethod
+ def _all_packages(pkg_name):
+ """
+ >>> list(install_lib._all_packages('foo.bar.baz'))
+ ['foo.bar.baz', 'foo.bar', 'foo']
+ """
+ while pkg_name:
+ yield pkg_name
+ pkg_name, sep, child = pkg_name.rpartition('.')
+
+ def _get_SVEM_NSPs(self):
+ """
+ Get namespace packages (list) but only for
+ single_version_externally_managed installations and empty otherwise.
+ """
+ # TODO: is it necessary to short-circuit here? i.e. what's the cost
+ # if get_finalized_command is called even when namespace_packages is
+ # False?
+ if not self.distribution.namespace_packages:
+ return []
+
+ install_cmd = self.get_finalized_command('install')
+ svem = install_cmd.single_version_externally_managed
+
+ return self.distribution.namespace_packages if svem else []
+
+ @staticmethod
+ def _gen_exclusion_paths():
+ """
+ Generate file paths to be excluded for namespace packages (bytecode
+ cache files).
+ """
+ # always exclude the package module itself
+ yield '__init__.py'
+
+ yield '__init__.pyc'
+ yield '__init__.pyo'
+
+ if not hasattr(imp, 'get_tag'):
+ return
+
+ base = os.path.join('__pycache__', '__init__.' + imp.get_tag())
+ yield base + '.pyc'
+ yield base + '.pyo'
def copy_tree(
self, infile, outfile,
diff --git a/setuptools/command/sdist.py b/setuptools/command/sdist.py
index c99ad9b1..a15582c3 100755
--- a/setuptools/command/sdist.py
+++ b/setuptools/command/sdist.py
@@ -9,6 +9,8 @@ import sys
import six
from setuptools import svn_utils
+from setuptools.utils import cs_path_exists
+
import pkg_resources
READMES = ('README', 'README.rst', 'README.txt')
@@ -147,7 +149,7 @@ class sdist(orig.sdist):
alts = fn
got_it = 0
for fn in alts:
- if os.path.exists(fn):
+ if cs_path_exists(fn):
got_it = 1
self.filelist.append(fn)
break
@@ -156,14 +158,14 @@ class sdist(orig.sdist):
self.warn("standard file not found: should have one of " +
', '.join(alts))
else:
- if os.path.exists(fn):
+ if cs_path_exists(fn):
self.filelist.append(fn)
else:
self.warn("standard file '%s' not found" % fn)
optional = ['test/test*.py', 'setup.cfg']
for pattern in optional:
- files = list(filter(os.path.isfile, glob(pattern)))
+ files = list(filter(cs_path_exists, glob(pattern)))
if files:
self.filelist.extend(files)
diff --git a/setuptools/dist.py b/setuptools/dist.py
index c6ac1946..26c35c4c 100644
--- a/setuptools/dist.py
+++ b/setuptools/dist.py
@@ -260,7 +260,7 @@ class Distribution(_Distribution):
self.dependency_links = attrs.pop('dependency_links', [])
assert_string_list(self,'dependency_links',self.dependency_links)
if attrs and 'setup_requires' in attrs:
- self.fetch_build_eggs(attrs.pop('setup_requires'))
+ self.fetch_build_eggs(attrs['setup_requires'])
for ep in pkg_resources.iter_entry_points('distutils.setup_keywords'):
if not hasattr(self,ep.name):
setattr(self,ep.name,None)
diff --git a/setuptools/extension.py b/setuptools/extension.py
index ab5908da..8178ed33 100644
--- a/setuptools/extension.py
+++ b/setuptools/extension.py
@@ -2,12 +2,16 @@ import sys
import re
import functools
import distutils.core
+import distutils.errors
import distutils.extension
-from setuptools.dist import _get_unpatched
+from .dist import _get_unpatched
+from . import msvc9_support
_Extension = _get_unpatched(distutils.core.Extension)
+msvc9_support.patch_for_specialized_compiler()
+
def have_pyrex():
"""
Return True if Cython or Pyrex can be imported.
diff --git a/setuptools/msvc9_support.py b/setuptools/msvc9_support.py
new file mode 100644
index 00000000..d0be70e2
--- /dev/null
+++ b/setuptools/msvc9_support.py
@@ -0,0 +1,64 @@
+import sys
+
+try:
+ import distutils.msvc9compiler
+except ImportError:
+ pass
+
+unpatched = dict()
+
+def patch_for_specialized_compiler():
+ """
+ Patch functions in distutils.msvc9compiler to use the standalone compiler
+ build for Python (Windows only). Fall back to original behavior when the
+ standalone compiler is not available.
+ """
+ if 'distutils' not in globals():
+ # The module isn't available to be patched
+ return
+
+ if unpatched:
+ # Already patched
+ return
+
+ unpatched.update(vars(distutils.msvc9compiler))
+
+ distutils.msvc9compiler.find_vcvarsall = find_vcvarsall
+ distutils.msvc9compiler.query_vcvarsall = query_vcvarsall
+
+def find_vcvarsall(version):
+ Reg = distutils.msvc9compiler.Reg
+ VC_BASE = r'Software\%sMicrosoft\DevDiv\VCForPython\%0.1f'
+ try:
+ # Per-user installs register the compiler path here
+ productdir = Reg.get_value(VC_BASE % ('', version), "installdir")
+ except KeyError:
+ try:
+ # All-user installs on a 64-bit system register here
+ productdir = Reg.get_value(VC_BASE % ('Wow6432Node\\', version), "installdir")
+ except KeyError:
+ productdir = None
+
+ if productdir:
+ import os
+ vcvarsall = os.path.join(productdir, "vcvarsall.bat")
+ if os.path.isfile(vcvarsall):
+ return vcvarsall
+
+ return unpatched['find_vcvarsall'](version)
+
+def query_vcvarsall(version, *args, **kwargs):
+ try:
+ return unpatched['query_vcvarsall'](version, *args, **kwargs)
+ except distutils.errors.DistutilsPlatformError:
+ exc = sys.exc_info()[1]
+ if exc and "vcvarsall.bat" in exc.args[0]:
+ message = 'Microsoft Visual C++ %0.1f is required (%s).' % (version, exc.args[0])
+ if int(version) == 9:
+ # This redirection link is maintained by Microsoft.
+ # Contact vspython@microsoft.com if it needs updating.
+ raise distutils.errors.DistutilsPlatformError(
+ message + ' Get it from http://aka.ms/vcpython27'
+ )
+ raise distutils.errors.DistutilsPlatformError(message)
+ raise
diff --git a/setuptools/sandbox.py b/setuptools/sandbox.py
index 185f2573..1d23ba98 100755
--- a/setuptools/sandbox.py
+++ b/setuptools/sandbox.py
@@ -30,7 +30,12 @@ def _execfile(filename, globals, locals=None):
"""
Python 3 implementation of execfile.
"""
- with open(filename, 'rb') as stream:
+ mode = 'rb'
+ # Python 2.6 compile requires LF for newlines, so use deprecated
+ # Universal newlines support.
+ if sys.version_info < (2, 7):
+ mode += 'U'
+ with open(filename, mode) as stream:
script = stream.read()
if locals is None:
locals = globals
diff --git a/setuptools/ssl_support.py b/setuptools/ssl_support.py
index b574f4b9..c618ea7c 100644
--- a/setuptools/ssl_support.py
+++ b/setuptools/ssl_support.py
@@ -173,12 +173,19 @@ class VerifyingHTTPSConn(HTTPSConnection):
if hasattr(self, '_tunnel') and getattr(self, '_tunnel_host', None):
self.sock = sock
self._tunnel()
+ # http://bugs.python.org/issue7776: Python>=3.4.1 and >=2.7.7
+ # change self.host to mean the proxy server host when tunneling is
+ # being used. Adapt, since we are interested in the destination
+ # host for the match_hostname() comparison.
+ actual_host = self._tunnel_host
+ else:
+ actual_host = self.host
self.sock = ssl.wrap_socket(
sock, cert_reqs=ssl.CERT_REQUIRED, ca_certs=self.ca_bundle
)
try:
- match_hostname(self.sock.getpeercert(), self.host)
+ match_hostname(self.sock.getpeercert(), actual_host)
except CertificateError:
self.sock.shutdown(socket.SHUT_RDWR)
self.sock.close()
diff --git a/setuptools/svn_utils.py b/setuptools/svn_utils.py
index 65e4b815..41d176bb 100644
--- a/setuptools/svn_utils.py
+++ b/setuptools/svn_utils.py
@@ -1,3 +1,5 @@
+from __future__ import absolute_import
+
import os
import re
import sys
diff --git a/setuptools/tests/test_integration.py b/setuptools/tests/test_integration.py
index 7144aa6c..8d6c1e55 100644
--- a/setuptools/tests/test_integration.py
+++ b/setuptools/tests/test_integration.py
@@ -25,6 +25,9 @@ def install_context(request, tmpdir, monkeypatch):
install_dir = tmpdir.mkdir('install_dir')
def fin():
+ # undo the monkeypatch, particularly needed under
+ # windows because of kept handle on cwd
+ monkeypatch.undo()
new_cwd.remove()
user_base.remove()
user_site.remove()
diff --git a/setuptools/tests/test_msvc9compiler.py b/setuptools/tests/test_msvc9compiler.py
new file mode 100644
index 00000000..970f7679
--- /dev/null
+++ b/setuptools/tests/test_msvc9compiler.py
@@ -0,0 +1,157 @@
+"""msvc9compiler monkey patch test
+
+This test ensures that importing setuptools is sufficient to replace
+the standard find_vcvarsall function with our patched version that
+finds the Visual C++ for Python package.
+"""
+
+import os
+import shutil
+import sys
+import tempfile
+import unittest
+import distutils.errors
+import contextlib
+
+# importing only setuptools should apply the patch
+__import__('setuptools')
+
+class MockReg:
+ """Mock for distutils.msvc9compiler.Reg. We patch it
+ with an instance of this class that mocks out the
+ functions that access the registry.
+ """
+
+ def __init__(self, hkey_local_machine={}, hkey_current_user={}):
+ self.hklm = hkey_local_machine
+ self.hkcu = hkey_current_user
+
+ def __enter__(self):
+ self.original_read_keys = distutils.msvc9compiler.Reg.read_keys
+ self.original_read_values = distutils.msvc9compiler.Reg.read_values
+
+ _winreg = getattr(distutils.msvc9compiler, '_winreg', None)
+ winreg = getattr(distutils.msvc9compiler, 'winreg', _winreg)
+
+ hives = {
+ winreg.HKEY_CURRENT_USER: self.hkcu,
+ winreg.HKEY_LOCAL_MACHINE: self.hklm,
+ }
+
+ def read_keys(cls, base, key):
+ """Return list of registry keys."""
+ hive = hives.get(base, {})
+ return [k.rpartition('\\')[2]
+ for k in hive if k.startswith(key.lower())]
+
+ def read_values(cls, base, key):
+ """Return dict of registry keys and values."""
+ hive = hives.get(base, {})
+ return dict((k.rpartition('\\')[2], hive[k])
+ for k in hive if k.startswith(key.lower()))
+
+ distutils.msvc9compiler.Reg.read_keys = classmethod(read_keys)
+ distutils.msvc9compiler.Reg.read_values = classmethod(read_values)
+
+ return self
+
+ def __exit__(self, exc_type, exc_value, exc_tb):
+ distutils.msvc9compiler.Reg.read_keys = self.original_read_keys
+ distutils.msvc9compiler.Reg.read_values = self.original_read_values
+
+@contextlib.contextmanager
+def patch_env(**replacements):
+ """
+ In a context, patch the environment with replacements. Pass None values
+ to clear the values.
+ """
+ saved = dict(
+ (key, os.environ['key'])
+ for key in replacements
+ if key in os.environ
+ )
+
+ # remove values that are null
+ remove = (key for (key, value) in replacements.items() if value is None)
+ for key in list(remove):
+ os.environ.pop(key, None)
+ replacements.pop(key)
+
+ os.environ.update(replacements)
+
+ try:
+ yield saved
+ finally:
+ for key in replacements:
+ os.environ.pop(key, None)
+ os.environ.update(saved)
+
+class TestMSVC9Compiler(unittest.TestCase):
+
+ def test_find_vcvarsall_patch(self):
+ if not hasattr(distutils, 'msvc9compiler'):
+ # skip
+ return
+
+ self.assertEqual(
+ "setuptools.msvc9_support",
+ distutils.msvc9compiler.find_vcvarsall.__module__,
+ "find_vcvarsall was not patched"
+ )
+
+ find_vcvarsall = distutils.msvc9compiler.find_vcvarsall
+ query_vcvarsall = distutils.msvc9compiler.query_vcvarsall
+
+ # No registry entries or environment variable means we should
+ # not find anything
+ with patch_env(VS90COMNTOOLS=None):
+ with MockReg():
+ self.assertIsNone(find_vcvarsall(9.0))
+
+ try:
+ query_vcvarsall(9.0)
+ self.fail('Expected DistutilsPlatformError from query_vcvarsall()')
+ except distutils.errors.DistutilsPlatformError:
+ exc_message = str(sys.exc_info()[1])
+ self.assertIn('aka.ms/vcpython27', exc_message)
+
+ key_32 = r'software\microsoft\devdiv\vcforpython\9.0\installdir'
+ key_64 = r'software\wow6432node\microsoft\devdiv\vcforpython\9.0\installdir'
+
+ # Make two mock files so we can tell whether HCKU entries are
+ # preferred to HKLM entries.
+ mock_installdir_1 = tempfile.mkdtemp()
+ mock_vcvarsall_bat_1 = os.path.join(mock_installdir_1, 'vcvarsall.bat')
+ open(mock_vcvarsall_bat_1, 'w').close()
+ mock_installdir_2 = tempfile.mkdtemp()
+ mock_vcvarsall_bat_2 = os.path.join(mock_installdir_2, 'vcvarsall.bat')
+ open(mock_vcvarsall_bat_2, 'w').close()
+ try:
+ # Ensure we get the current user's setting first
+ with MockReg(
+ hkey_current_user={key_32: mock_installdir_1},
+ hkey_local_machine={
+ key_32: mock_installdir_2,
+ key_64: mock_installdir_2,
+ }
+ ):
+ self.assertEqual(mock_vcvarsall_bat_1, find_vcvarsall(9.0))
+
+ # Ensure we get the local machine value if it's there
+ with MockReg(hkey_local_machine={key_32: mock_installdir_2}):
+ self.assertEqual(mock_vcvarsall_bat_2, find_vcvarsall(9.0))
+
+ # Ensure we prefer the 64-bit local machine key
+ # (*not* the Wow6432Node key)
+ with MockReg(
+ hkey_local_machine={
+ # This *should* only exist on 32-bit machines
+ key_32: mock_installdir_1,
+ # This *should* only exist on 64-bit machines
+ key_64: mock_installdir_2,
+ }
+ ):
+ self.assertEqual(mock_vcvarsall_bat_1, find_vcvarsall(9.0))
+ finally:
+ shutil.rmtree(mock_installdir_1)
+ shutil.rmtree(mock_installdir_2)
diff --git a/setuptools/tests/test_resources.py b/setuptools/tests/test_resources.py
index 2db87efa..b688cfe0 100644
--- a/setuptools/tests/test_resources.py
+++ b/setuptools/tests/test_resources.py
@@ -15,14 +15,10 @@ from pkg_resources import (parse_requirements, VersionConflict, parse_version,
from setuptools.command.easy_install import (get_script_header, is_sh,
nt_quote_arg)
+from .py26compat import skipIf
import six
-try:
- frozenset
-except NameError:
- from sets import ImmutableSet as frozenset
-
def safe_repr(obj, short=False):
""" copied from Python2.7"""
try:
@@ -576,13 +572,8 @@ class NamespaceTests(TestCase):
pkg_resources._namespace_packages = self._ns_pkgs.copy()
sys.path = self._prev_sys_path[:]
- def _assertIn(self, member, container):
- """ assertIn and assertTrue does not exist in Python2.3"""
- if member not in container:
- standardMsg = '%s not found in %s' % (safe_repr(member),
- safe_repr(container))
- self.fail(self._formatMessage(msg, standardMsg))
-
+ msg = "Test fails when /tmp is a symlink. See #231"
+ @skipIf(os.path.islink(tempfile.gettempdir()), msg)
def test_two_levels_deep(self):
"""
Test nested namespace packages
@@ -606,15 +597,17 @@ class NamespaceTests(TestCase):
pkg2_init.write(ns_str)
pkg2_init.close()
import pkg1
- self._assertIn("pkg1", pkg_resources._namespace_packages.keys())
+ assert "pkg1" in pkg_resources._namespace_packages
try:
import pkg1.pkg2
except ImportError:
self.fail("Setuptools tried to import the parent namespace package")
# check the _namespace_packages dict
- self._assertIn("pkg1.pkg2", pkg_resources._namespace_packages.keys())
- self.assertEqual(pkg_resources._namespace_packages["pkg1"], ["pkg1.pkg2"])
+ assert "pkg1.pkg2" in pkg_resources._namespace_packages
+ assert pkg_resources._namespace_packages["pkg1"] == ["pkg1.pkg2"]
# check the __path__ attribute contains both paths
- self.assertEqual(pkg1.pkg2.__path__, [
+ expected = [
os.path.join(self._tmpdir, "site-pkgs", "pkg1", "pkg2"),
- os.path.join(self._tmpdir, "site-pkgs2", "pkg1", "pkg2")])
+ os.path.join(self._tmpdir, "site-pkgs2", "pkg1", "pkg2"),
+ ]
+ assert pkg1.pkg2.__path__ == expected
diff --git a/setuptools/tests/test_sandbox.py b/setuptools/tests/test_sandbox.py
index 06b3d434..6a890ebc 100644
--- a/setuptools/tests/test_sandbox.py
+++ b/setuptools/tests/test_sandbox.py
@@ -19,7 +19,7 @@ def has_win32com():
if not sys.platform.startswith('win32'):
return False
try:
- mod = __import__('win32com')
+ __import__('win32com')
except ImportError:
return False
return True
@@ -33,8 +33,6 @@ class TestSandbox(unittest.TestCase):
shutil.rmtree(self.dir)
def test_devnull(self):
- if sys.version < '2.4':
- return
sandbox = DirectorySandbox(self.dir)
sandbox.run(self._file_writer(os.devnull))
@@ -75,5 +73,11 @@ class TestSandbox(unittest.TestCase):
setuptools.sandbox._execfile(target, vars(namespace))
assert namespace.result == 'passed'
+ def test_setup_py_with_CRLF(self):
+ setup_py = os.path.join(self.dir, 'setup.py')
+ with open(setup_py, 'wb') as stream:
+ stream.write(b'"degenerate script"\r\n')
+ setuptools.sandbox._execfile(setup_py, globals())
+
if __name__ == '__main__':
unittest.main()
diff --git a/setuptools/tests/test_sdist.py b/setuptools/tests/test_sdist.py
index c78e5b0f..26b072cc 100644
--- a/setuptools/tests/test_sdist.py
+++ b/setuptools/tests/test_sdist.py
@@ -87,6 +87,7 @@ class TestSdistTest(unittest.TestCase):
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)
@@ -122,6 +123,33 @@ class TestSdistTest(unittest.TestCase):
self.assertTrue(os.path.join('sdist_test', 'b.txt') in manifest)
self.assertTrue(os.path.join('sdist_test', 'c.rst') not in manifest)
+
+ def test_defaults_case_sensitivity(self):
+ """
+ Make sure default files (README.*, etc.) are added in a case-sensitive
+ way to avoid problems with packages built on Windows.
+ """
+
+ open(os.path.join(self.temp_dir, 'readme.rst'), 'w').close()
+ open(os.path.join(self.temp_dir, 'SETUP.cfg'), 'w').close()
+
+ dist = Distribution(SETUP_ATTRS)
+ # the extension deliberately capitalized for this test
+ # to make sure the actual filename (not capitalized) gets added
+ # to the manifest
+ dist.script_name = 'setup.PY'
+ cmd = sdist(dist)
+ cmd.ensure_finalized()
+
+ with quiet():
+ cmd.run()
+
+ # lowercase all names so we can test in a case-insensitive way to make sure the files are not included
+ manifest = map(lambda x: x.lower(), cmd.filelist.files)
+ self.assertFalse('readme.rst' in manifest, manifest)
+ self.assertFalse('setup.py' in manifest, manifest)
+ self.assertFalse('setup.cfg' in manifest, manifest)
+
def test_manifest_is_written_with_utf8_encoding(self):
# Test for #303.
dist = Distribution(SETUP_ATTRS)
diff --git a/setuptools/tests/win_script_wrapper.txt b/setuptools/tests/win_script_wrapper.txt
index 731243dd..b3a52e0a 100644
--- a/setuptools/tests/win_script_wrapper.txt
+++ b/setuptools/tests/win_script_wrapper.txt
@@ -3,7 +3,7 @@ Python Script Wrapper for Windows
setuptools includes wrappers for Python scripts that allows them to be
executed like regular windows programs. There are 2 wrappers, once
-for command-line programs, cli.exe, and one for graphica programs,
+for command-line programs, cli.exe, and one for graphical programs,
gui.exe. These programs are almost identical, function pretty much
the same way, and are generated from the same source file. The
wrapper programs are used by copying them to the directory containing
@@ -44,7 +44,7 @@ We'll also copy cli.exe to the sample-directory with the name foo.exe:
When the copy of cli.exe, foo.exe in this example, runs, it examines
the path name it was run with and computes a Python script path name
-by removing the '.exe' suffic and adding the '-script.py' suffix. (For
+by removing the '.exe' suffix and adding the '-script.py' suffix. (For
GUI programs, the suffix '-script-pyw' is added.) This is why we
named out script the way we did. Now we can run out script by running
the wrapper:
@@ -68,8 +68,8 @@ This example was a little pathological in that it exercised windows
- Double quotes in strings need to be escaped by preceding them with
back slashes.
-- One or more backslashes preceding double quotes quotes need to be
- escaped by preceding each of them them with back slashes.
+- One or more backslashes preceding double quotes need to be escaped
+ by preceding each of them with back slashes.
Specifying Python Command-line Options
diff --git a/setuptools/utils.py b/setuptools/utils.py
new file mode 100644
index 00000000..91e4b87f
--- /dev/null
+++ b/setuptools/utils.py
@@ -0,0 +1,11 @@
+import os
+import os.path
+
+
+def cs_path_exists(fspath):
+ if not os.path.exists(fspath):
+ return False
+ # make absolute so we always have a directory
+ abspath = os.path.abspath(fspath)
+ directory, filename = os.path.split(abspath)
+ return filename in os.listdir(directory) \ No newline at end of file
diff --git a/setuptools/version.py b/setuptools/version.py
index 773d9307..c974945d 100644
--- a/setuptools/version.py
+++ b/setuptools/version.py
@@ -1 +1 @@
-__version__ = '5.5'
+__version__ = '6.0.2'