Hello community,

here is the log from the commit of package python3-setuptools for 
openSUSE:Factory checked in at 2015-01-21 21:54:36
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python3-setuptools (Old)
 and      /work/SRC/openSUSE:Factory/.python3-setuptools.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python3-setuptools"

Changes:
--------
--- /work/SRC/openSUSE:Factory/python3-setuptools/python3-setuptools.changes    
2015-01-08 23:05:30.000000000 +0100
+++ 
/work/SRC/openSUSE:Factory/.python3-setuptools.new/python3-setuptools.changes   
    2015-01-21 21:54:40.000000000 +0100
@@ -1,0 +2,36 @@
+Tue Jan 20 19:45:50 UTC 2015 - [email protected]
+
+- update to version 12.0.3:
+  * Fixed incorrect class attribute in ``install_scripts``. Tests
+    would be nice.
+
+- changes to version 12.0.2:
+  * Issue #331: Fixed ``install_scripts`` command on Windows systems
+    corrupting the header.
+
+-------------------------------------------------------------------
+Sat Jan 17 18:59:40 UTC 2015 - [email protected]
+
+- update to version 12.0.1:
+  * Restore "setuptools.command.easy_install.sys_executable" for pbr
+    compatibility. For the future, tools should construct a
+    CommandSpec explicitly.
+
+- changes from version 12.0:
+  * Issue #188: Setuptools now support multiple entities in the value
+    for "build.executable", such that an executable of "/usr/bin/env
+    my-python" may be specified. This means that systems with a
+    specified executable whose name has spaces in the path must be
+    updated to escape or quote that value.
+  * Deprecated "easy_install.ScriptWriter.get_writer", replaced by
+    ".best()" with slightly different semantics (no force_windows
+    flag).
+
+-------------------------------------------------------------------
+Sun Jan 10  00:51:53 UTC 2015 - [email protected]
+
+- specfile:
+  * update copyright year
+  * remove ifs for opensuse version <=1220
+
+-------------------------------------------------------------------

Old:
----
  setuptools-11.3.1.tar.gz

New:
----
  setuptools-12.0.3.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python3-setuptools.spec ++++++
--- /var/tmp/diff_new_pack.CB3j1B/_old  2015-01-21 21:54:41.000000000 +0100
+++ /var/tmp/diff_new_pack.CB3j1B/_new  2015-01-21 21:54:41.000000000 +0100
@@ -17,7 +17,7 @@
 
 
 Name:           python3-setuptools
-Version:        11.3.1
+Version:        12.0.3
 Release:        0
 Url:            http://pypi.python.org/pypi/setuptools
 Summary:        Easily download, build, install, upgrade, and uninstall Python 
packages
@@ -32,10 +32,6 @@
 #NOTE(saschpe): Need 'python3' for the 'xml' module:
 BuildRequires:  python3
 Requires:       python3
-%if 0%{?suse_version} == 1220
-BuildRequires:  python3-2to3
-BuildRequires:  python3-xml
-%endif
 BuildRequires:  python3-devel
 Requires(post): update-alternatives
 Requires(postun): update-alternatives

++++++ setuptools-11.3.1.tar.gz -> setuptools-12.0.3.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/setuptools-11.3.1/CHANGES.txt 
new/setuptools-12.0.3/CHANGES.txt
--- old/setuptools-11.3.1/CHANGES.txt   2015-01-06 15:47:44.000000000 +0100
+++ new/setuptools-12.0.3/CHANGES.txt   2015-01-19 02:48:13.000000000 +0100
@@ -3,6 +3,38 @@
 =======
 
 ------
+12.0.3
+------
+
+* Fixed incorrect class attribute in ``install_scripts``. Tests would be nice.
+
+------
+12.0.2
+------
+
+* Issue #331: Fixed ``install_scripts`` command on Windows systems corrupting
+  the header.
+
+------
+12.0.1
+------
+
+* Restore ``setuptools.command.easy_install.sys_executable`` for pbr
+  compatibility. For the future, tools should construct a CommandSpec
+  explicitly.
+
+----
+12.0
+----
+
+* Issue #188: Setuptools now support multiple entities in the value for
+  ``build.executable``, such that an executable of "/usr/bin/env my-python" may
+  be specified. This means that systems with a specified executable whose name
+  has spaces in the path must be updated to escape or quote that value.
+* Deprecated ``easy_install.ScriptWriter.get_writer``, replaced by ``.best()``
+  with slightly different semantics (no force_windows flag).
+
+------
 11.3.1
 ------
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/setuptools-11.3.1/MANIFEST.in 
new/setuptools-12.0.3/MANIFEST.in
--- old/setuptools-11.3.1/MANIFEST.in   2015-01-05 18:59:01.000000000 +0100
+++ new/setuptools-12.0.3/MANIFEST.in   2015-01-19 00:48:57.000000000 +0100
@@ -1,5 +1,5 @@
 recursive-include setuptools *.py *.exe *.xml
-recursive-include tests *.py *.c *.pyx
+recursive-include tests *.py
 recursive-include setuptools/tests *.html
 recursive-include docs *.py *.txt *.conf *.css *.css_t Makefile 
indexsidebar.html
 recursive-include _markerlib *.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/setuptools-11.3.1/PKG-INFO 
new/setuptools-12.0.3/PKG-INFO
--- old/setuptools-11.3.1/PKG-INFO      2015-01-06 16:11:58.000000000 +0100
+++ new/setuptools-12.0.3/PKG-INFO      2015-01-19 02:48:36.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: setuptools
-Version: 11.3.1
+Version: 12.0.3
 Summary: Easily download, build, install, upgrade, and uninstall Python 
packages
 Home-page: https://bitbucket.org/pypa/setuptools
 Author: Python Packaging Authority
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/setuptools-11.3.1/ez_setup.py 
new/setuptools-12.0.3/ez_setup.py
--- old/setuptools-11.3.1/ez_setup.py   2015-01-06 16:11:49.000000000 +0100
+++ new/setuptools-12.0.3/ez_setup.py   2015-01-19 02:43:32.000000000 +0100
@@ -36,7 +36,7 @@
 except ImportError:
     USER_SITE = None
 
-DEFAULT_VERSION = "11.3.1"
+DEFAULT_VERSION = "12.0.3"
 DEFAULT_URL = "https://pypi.python.org/packages/source/s/setuptools/";
 
 def _python_cmd(*args):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/setuptools-11.3.1/setup.py 
new/setuptools-12.0.3/setup.py
--- old/setuptools-11.3.1/setup.py      2015-01-04 17:22:03.000000000 +0100
+++ new/setuptools-12.0.3/setup.py      2015-01-19 00:48:57.000000000 +0100
@@ -170,8 +170,7 @@
     tests_require=[
         'setuptools[ssl]',
         'pytest',
-        'mock',
-    ],
+    ] + (['mock'] if sys.version_info[:2] < (3, 3) else []),
     setup_requires=[
     ] + pytest_runner,
 )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/setuptools-11.3.1/setuptools/command/easy_install.py 
new/setuptools-12.0.3/setuptools/command/easy_install.py
--- old/setuptools-11.3.1/setuptools/command/easy_install.py    2015-01-05 
18:59:01.000000000 +0100
+++ new/setuptools-12.0.3/setuptools/command/easy_install.py    2015-01-19 
02:21:47.000000000 +0100
@@ -35,6 +35,8 @@
 import site
 import struct
 import contextlib
+import subprocess
+import shlex
 
 from setuptools import Command
 from setuptools.sandbox import run_setup
@@ -54,15 +56,10 @@
 )
 import pkg_resources
 
-
 # Turn on PEP440Warnings
 warnings.filterwarnings("default", category=pkg_resources.PEP440Warning)
 
 
-sys_executable = os.environ.get('__PYVENV_LAUNCHER__',
-                                os.path.normpath(sys.executable))
-
-
 __all__ = [
     'samefile', 'easy_install', 'PthDistributions', 'extract_wininst_cfg',
     'main', 'get_exe_prefixes',
@@ -448,43 +445,49 @@
             self.pth_file = None  # and don't create a .pth file
         self.install_dir = instdir
 
-    def cant_write_to_target(self):
-        template = """can't create or remove files in install directory
+    __cant_write_msg = textwrap.dedent("""
+        can't create or remove files in install directory
 
-The following error occurred while trying to add or remove files in the
-installation directory:
+        The following error occurred while trying to add or remove files in the
+        installation directory:
 
-    %s
+            %s
 
-The installation directory you specified (via --install-dir, --prefix, or
-the distutils default setting) was:
+        The installation directory you specified (via --install-dir, --prefix, 
or
+        the distutils default setting) was:
 
-    %s
-"""
-        msg = template % (sys.exc_info()[1], self.install_dir,)
+            %s
+        """).lstrip()
 
-        if not os.path.exists(self.install_dir):
-            msg += """
-This directory does not currently exist.  Please create it and try again, or
-choose a different installation directory (using the -d or --install-dir
-option).
-"""
-        else:
-            msg += """
-Perhaps your account does not have write access to this directory?  If the
-installation directory is a system-owned directory, you may need to sign in
-as the administrator or "root" account.  If you do not have administrative
-access to this machine, you may wish to choose a different installation
-directory, preferably one that is listed in your PYTHONPATH environment
-variable.
+    __not_exists_id = textwrap.dedent("""
+        This directory does not currently exist.  Please create it and try 
again, or
+        choose a different installation directory (using the -d or 
--install-dir
+        option).
+        """).lstrip()
+
+    __access_msg = textwrap.dedent("""
+        Perhaps your account does not have write access to this directory?  If 
the
+        installation directory is a system-owned directory, you may need to 
sign in
+        as the administrator or "root" account.  If you do not have 
administrative
+        access to this machine, you may wish to choose a different installation
+        directory, preferably one that is listed in your PYTHONPATH environment
+        variable.
+
+        For information on other options, you may wish to consult the
+        documentation at:
 
-For information on other options, you may wish to consult the
-documentation at:
+          https://pythonhosted.org/setuptools/easy_install.html
 
-  https://pythonhosted.org/setuptools/easy_install.html
+        Please make the appropriate changes for your system and try again.
+        """).lstrip()
+
+    def cant_write_to_target(self):
+        msg = self._cant_write_msg % (sys.exc_info()[1], self.install_dir,)
 
-Please make the appropriate changes for your system and try again.
-"""
+        if not os.path.exists(self.install_dir):
+            msg += '\n' + self.__not_exists_id
+        else:
+            msg += '\n' + self.__access_msg
         raise DistutilsError(msg)
 
     def check_pth_processing(self):
@@ -744,7 +747,7 @@
 
     def install_wrapper_scripts(self, dist):
         if not self.exclude_scripts:
-            for args in get_script_args(dist):
+            for args in ScriptWriter.best().get_args(dist):
                 self.write_script(*args)
 
     def install_script(self, dist, script_name, script_text, dev_path=None):
@@ -753,7 +756,7 @@
         is_script = is_python_script(script_text, script_name)
 
         if is_script:
-            script_text = (get_script_header(script_text) +
+            script_text = (ScriptWriter.get_header(script_text) +
                            self._load_template(dev_path) % locals())
         self.write_script(script_name, _to_ascii(script_text), 'b')
 
@@ -917,9 +920,10 @@
                     f.write('%s: %s\n' % (k.replace('_', '-').title(), v))
             f.close()
         script_dir = os.path.join(_egg_info, 'scripts')
-        self.delete_blockers(  # delete entry-point scripts to avoid duping
+        # delete entry-point scripts to avoid duping
+        self.delete_blockers(
             [os.path.join(script_dir, args[0]) for args in
-             get_script_args(dist)]
+             ScriptWriter.get_args(dist)]
         )
         # Build .egg file from tmpdir
         bdist_egg.make_zipfile(
@@ -981,46 +985,52 @@
                     f.write('\n'.join(locals()[name]) + '\n')
                     f.close()
 
+    __mv_warning = textwrap.dedent("""
+        Because this distribution was installed --multi-version, before you can
+        import modules from this package in an application, you will need to
+        'import pkg_resources' and then use a 'require()' call similar to one 
of
+        these examples, in order to select the desired version:
+
+            pkg_resources.require("%(name)s")  # latest installed version
+            pkg_resources.require("%(name)s==%(version)s")  # this exact 
version
+            pkg_resources.require("%(name)s>=%(version)s")  # this version or 
higher
+        """).lstrip()
+
+    __id_warning = textwrap.dedent("""
+        Note also that the installation directory must be on sys.path at 
runtime for
+        this to work.  (e.g. by being the application's script directory, by 
being on
+        PYTHONPATH, or by being added to sys.path by your code.)
+        """)
+
     def installation_report(self, req, dist, what="Installed"):
         """Helpful installation message for display to package users"""
         msg = "\n%(what)s %(eggloc)s%(extras)s"
         if self.multi_version and not self.no_report:
-            msg += """
-
-Because this distribution was installed --multi-version, before you can
-import modules from this package in an application, you will need to
-'import pkg_resources' and then use a 'require()' call similar to one of
-these examples, in order to select the desired version:
-
-    pkg_resources.require("%(name)s")  # latest installed version
-    pkg_resources.require("%(name)s==%(version)s")  # this exact version
-    pkg_resources.require("%(name)s>=%(version)s")  # this version or higher
-"""
+            msg += '\n' + self.__mv_warning
             if self.install_dir not in map(normalize_path, sys.path):
-                msg += """
+                msg += '\n' + self.__id_warning
 
-Note also that the installation directory must be on sys.path at runtime for
-this to work.  (e.g. by being the application's script directory, by being on
-PYTHONPATH, or by being added to sys.path by your code.)
-"""
         eggloc = dist.location
         name = dist.project_name
         version = dist.version
         extras = ''  # TODO: self.report_extras(req, dist)
         return msg % locals()
 
-    def report_editable(self, spec, setup_script):
-        dirname = os.path.dirname(setup_script)
-        python = sys.executable
-        return """\nExtracted editable version of %(spec)s to %(dirname)s
+    __editable_msg = textwrap.dedent("""
+        Extracted editable version of %(spec)s to %(dirname)s
 
-If it uses setuptools in its setup script, you can activate it in
-"development" mode by going to that directory and running::
+        If it uses setuptools in its setup script, you can activate it in
+        "development" mode by going to that directory and running::
 
-    %(python)s setup.py develop
+            %(python)s setup.py develop
 
-See the setuptools documentation for the "develop" command for more info.
-""" % locals()
+        See the setuptools documentation for the "develop" command for more 
info.
+        """).lstrip()
+
+    def report_editable(self, spec, setup_script):
+        dirname = os.path.dirname(setup_script)
+        python = sys.executable
+        return '\n' + self.__editable_msg % locals()
 
     def run_setup(self, setup_script, setup_base, args):
         sys.modules.setdefault('distutils.command.bdist_egg', bdist_egg)
@@ -1171,35 +1181,38 @@
         finally:
             log.set_verbosity(self.verbose)  # restore original verbosity
 
-    def no_default_version_msg(self):
-        template = """bad install directory or PYTHONPATH
+    __no_default_msg = textwrap.dedent("""
+        bad install directory or PYTHONPATH
 
-You are attempting to install a package to a directory that is not
-on PYTHONPATH and which Python does not read ".pth" files from.  The
-installation directory you specified (via --install-dir, --prefix, or
-the distutils default setting) was:
+        You are attempting to install a package to a directory that is not
+        on PYTHONPATH and which Python does not read ".pth" files from.  The
+        installation directory you specified (via --install-dir, --prefix, or
+        the distutils default setting) was:
 
-    %s
+            %s
 
-and your PYTHONPATH environment variable currently contains:
+        and your PYTHONPATH environment variable currently contains:
 
-    %r
+            %r
 
-Here are some of your options for correcting the problem:
+        Here are some of your options for correcting the problem:
 
-* You can choose a different installation directory, i.e., one that is
-  on PYTHONPATH or supports .pth files
+        * You can choose a different installation directory, i.e., one that is
+          on PYTHONPATH or supports .pth files
 
-* You can add the installation directory to the PYTHONPATH environment
-  variable.  (It must then also be on PYTHONPATH whenever you run
-  Python and want to use the package(s) you are installing.)
+        * You can add the installation directory to the PYTHONPATH environment
+          variable.  (It must then also be on PYTHONPATH whenever you run
+          Python and want to use the package(s) you are installing.)
 
-* You can set up the installation directory to support ".pth" files by
-  using one of the approaches described here:
+        * You can set up the installation directory to support ".pth" files by
+          using one of the approaches described here:
 
-  
https://pythonhosted.org/setuptools/easy_install.html#custom-installation-locations
+          
https://pythonhosted.org/setuptools/easy_install.html#custom-installation-locations
 
-Please make the appropriate changes for your system and try again."""
+        Please make the appropriate changes for your system and try 
again.""").lstrip()
+
+    def no_default_version_msg(self):
+        template = self.__no_default_msg
         return template % (self.install_dir, os.environ.get('PYTHONPATH', ''))
 
     def install_site_py(self):
@@ -1590,33 +1603,6 @@
     return re.compile(first_line_re.pattern.decode())
 
 
-def get_script_header(script_text, executable=sys_executable, wininst=False):
-    """Create a #! line, getting options (if any) from script_text"""
-    first = (script_text + '\n').splitlines()[0]
-    match = _first_line_re().match(first)
-    options = ''
-    if match:
-        options = match.group(1) or ''
-        if options:
-            options = ' ' + options
-    if wininst:
-        executable = "python.exe"
-    else:
-        executable = nt_quote_arg(executable)
-    hdr = "#!%(executable)s%(options)s\n" % locals()
-    if not isascii(hdr):
-        # Non-ascii path to sys.executable, use -x to prevent warnings
-        if options:
-            if options.strip().startswith('-'):
-                options = ' -x' + options.strip()[1:]
-                # else: punt, we can't do it, let the warning happen anyway
-        else:
-            options = ' -x'
-    executable = fix_jython_executable(executable, options)
-    hdr = "#!%(executable)s%(options)s\n" % locals()
-    return hdr
-
-
 def auto_chmod(func, arg, exc):
     if func is os.remove and os.name == 'nt':
         chmod(arg, stat.S_IWRITE)
@@ -1825,36 +1811,7 @@
 
 def nt_quote_arg(arg):
     """Quote a command line argument according to Windows parsing rules"""
-
-    result = []
-    needquote = False
-    nb = 0
-
-    needquote = (" " in arg) or ("\t" in arg)
-    if needquote:
-        result.append('"')
-
-    for c in arg:
-        if c == '\\':
-            nb += 1
-        elif c == '"':
-            # double preceding backslashes, then add a \"
-            result.append('\\' * (nb * 2) + '\\"')
-            nb = 0
-        else:
-            if nb:
-                result.append('\\' * nb)
-                nb = 0
-            result.append(c)
-
-    if nb:
-        result.append('\\' * nb)
-
-    if needquote:
-        result.append('\\' * nb)  # double the trailing backslashes
-        result.append('"')
-
-    return ''.join(result)
+    return subprocess.list2cmdline([arg])
 
 
 def is_python_script(script_text, filename):
@@ -1909,6 +1866,115 @@
     return executable
 
 
+class CommandSpec(list):
+    """
+    A command spec for a #! header, specified as a list of arguments akin to
+    those passed to Popen.
+    """
+
+    options = []
+    split_args = dict()
+
+    @classmethod
+    def _sys_executable(cls):
+        _default = os.path.normpath(sys.executable)
+        return os.environ.get('__PYVENV_LAUNCHER__', _default)
+
+    @classmethod
+    def from_param(cls, param):
+        """
+        Construct a CommandSpec from a parameter to build_scripts, which may
+        be None.
+        """
+        if isinstance(param, cls):
+            return param
+        if isinstance(param, list):
+            return cls(param)
+        if param is None:
+            return cls.from_environment()
+        # otherwise, assume it's a string.
+        return cls.from_string(param)
+
+    @classmethod
+    def from_environment(cls):
+        return cls.from_string('"' + cls._sys_executable() + '"')
+
+    @classmethod
+    def from_string(cls, string):
+        """
+        Construct a command spec from a simple string representing a command
+        line parseable by shlex.split.
+        """
+        items = shlex.split(string, **cls.split_args)
+        return JythonCommandSpec.from_string(string) or cls(items)
+
+    def install_options(self, script_text):
+        self.options = shlex.split(self._extract_options(script_text))
+        cmdline = subprocess.list2cmdline(self)
+        if not isascii(cmdline):
+            self.options[:0] = ['-x']
+
+    @staticmethod
+    def _extract_options(orig_script):
+        """
+        Extract any options from the first line of the script.
+        """
+        first = (orig_script + '\n').splitlines()[0]
+        match = _first_line_re().match(first)
+        options = match.group(1) or '' if match else ''
+        return options.strip()
+
+    def as_header(self):
+        return self._render(self + list(self.options))
+
+    @staticmethod
+    def _render(items):
+        cmdline = subprocess.list2cmdline(items)
+        return '#!' + cmdline + '\n'
+
+# For pbr compat; will be removed in a future version.
+sys_executable = CommandSpec._sys_executable()
+
+
+class WindowsCommandSpec(CommandSpec):
+    split_args = dict(posix=False)
+
+
+class JythonCommandSpec(CommandSpec):
+    @classmethod
+    def from_string(cls, string):
+        """
+        On Jython, construct an instance of this class.
+        On platforms other than Jython, return None.
+        """
+        needs_jython_spec = (
+            sys.platform.startswith('java')
+            and
+            __import__('java').lang.System.getProperty('os.name') != 'Linux'
+        )
+        return cls([string]) if needs_jython_spec else None
+
+    def as_header(self):
+        """
+        Workaround Jython's sys.executable being a .sh (an invalid
+        shebang line interpreter)
+        """
+        if not is_sh(self[0]):
+            return super(JythonCommandSpec, self).as_header()
+
+        if self.options:
+            # Can't apply the workaround, leave it broken
+            log.warn(
+                "WARNING: Unable to adapt shebang line for Jython,"
+                " the following script is NOT executable\n"
+                "         see http://bugs.jython.org/issue1112 for"
+                " more information.")
+            return super(JythonCommandSpec, self).as_header()
+
+        items = ['/usr/bin/env'] + self + list(self.options)
+        return self._render(items)
+
+
 class ScriptWriter(object):
     """
     Encapsulates behavior around writing entry point scripts for console and
@@ -1927,39 +1993,81 @@
             )
     """).lstrip()
 
+    command_spec_class = CommandSpec
+
+    @classmethod
+    def get_script_args(cls, dist, executable=None, wininst=False):
+        # for backward compatibility
+        warnings.warn("Use get_args", DeprecationWarning)
+        writer = (WindowsScriptWriter if wininst else ScriptWriter).best()
+        header = cls.get_script_header("", executable, wininst)
+        return writer.get_args(dist, header)
+
     @classmethod
-    def get_script_args(cls, dist, executable=sys_executable, wininst=False):
+    def get_script_header(cls, script_text, executable=None, wininst=False):
+        # for backward compatibility
+        warnings.warn("Use get_header", DeprecationWarning)
+        if wininst:
+            executable = "python.exe"
+        cmd = cls.command_spec_class.from_param(executable)
+        cmd.install_options(script_text)
+        return cmd.as_header()
+
+    @classmethod
+    def get_args(cls, dist, header=None):
         """
         Yield write_script() argument tuples for a distribution's entrypoints
         """
-        gen_class = cls.get_writer(wininst)
+        if header is None:
+            header = cls.get_header()
         spec = str(dist.as_requirement())
-        header = get_script_header("", executable, wininst)
         for type_ in 'console', 'gui':
             group = type_ + '_scripts'
             for name, ep in dist.get_entry_map(group).items():
-                script_text = gen_class.template % locals()
-                for res in gen_class._get_script_args(type_, name, header,
-                                                      script_text):
+                script_text = cls.template % locals()
+                for res in cls._get_script_args(type_, name, header,
+                        script_text):
                     yield res
 
     @classmethod
     def get_writer(cls, force_windows):
-        if force_windows or sys.platform == 'win32':
-            return WindowsScriptWriter.get_writer()
-        return cls
+        # for backward compatibility
+        warnings.warn("Use best", DeprecationWarning)
+        return WindowsScriptWriter.best() if force_windows else cls.best()
+
+    @classmethod
+    def best(cls):
+        """
+        Select the best ScriptWriter for this environment.
+        """
+        return WindowsScriptWriter.best() if sys.platform == 'win32' else cls
 
     @classmethod
     def _get_script_args(cls, type_, name, header, script_text):
         # Simply write the stub with no extension.
         yield (name, header + script_text)
 
+    @classmethod
+    def get_header(cls, script_text="", executable=None):
+        """Create a #! line, getting options (if any) from script_text"""
+        cmd = cls.command_spec_class.from_param(executable)
+        cmd.install_options(script_text)
+        return cmd.as_header()
+
 
 class WindowsScriptWriter(ScriptWriter):
+    command_spec_class = WindowsCommandSpec
+
     @classmethod
     def get_writer(cls):
+        # for backward compatibility
+        warnings.warn("Use best", DeprecationWarning)
+        return cls.best()
+
+    @classmethod
+    def best(cls):
         """
-        Get a script writer suitable for Windows
+        Select the best ScriptWriter suitable for Windows
         """
         writer_lookup = dict(
             executable=WindowsExecutableLauncherWriter,
@@ -2034,6 +2142,7 @@
 
 # for backward-compatibility
 get_script_args = ScriptWriter.get_script_args
+get_script_header = ScriptWriter.get_script_header
 
 
 def get_win_launcher(type):
@@ -2155,4 +2264,3 @@
         yield
     finally:
         distutils.core.gen_usage = saved
-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/setuptools-11.3.1/setuptools/command/install_scripts.py 
new/setuptools-12.0.3/setuptools/command/install_scripts.py
--- old/setuptools-11.3.1/setuptools/command/install_scripts.py 2015-01-05 
18:51:43.000000000 +0100
+++ new/setuptools-12.0.3/setuptools/command/install_scripts.py 2015-01-19 
02:45:22.000000000 +0100
@@ -13,8 +13,7 @@
         self.no_ep = False
 
     def run(self):
-        from setuptools.command.easy_install import get_script_args
-        from setuptools.command.easy_install import sys_executable
+        import setuptools.command.easy_install as ei
 
         self.run_command("egg_info")
         if self.distribution.scripts:
@@ -31,11 +30,17 @@
             ei_cmd.egg_name, ei_cmd.egg_version,
         )
         bs_cmd = self.get_finalized_command('build_scripts')
-        executable = getattr(bs_cmd, 'executable', sys_executable)
-        is_wininst = getattr(
-            self.get_finalized_command("bdist_wininst"), '_is_running', False
-        )
-        for args in get_script_args(dist, executable, is_wininst):
+        exec_param = getattr(bs_cmd, 'executable', None)
+        bw_cmd = self.get_finalized_command("bdist_wininst")
+        is_wininst = getattr(bw_cmd, '_is_running', False)
+        writer = ei.ScriptWriter
+        if is_wininst:
+            exec_param = "python.exe"
+            writer = ei.WindowsScriptWriter
+        # resolve the writer to the environment
+        writer = writer.best()
+        cmd = writer.command_spec_class.from_param(exec_param)
+        for args in writer.get_args(dist, cmd.as_header()):
             self.write_script(*args)
 
     def write_script(self, script_name, contents, mode="t", *ignored):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/setuptools-11.3.1/setuptools/msvc9_support.py 
new/setuptools-12.0.3/setuptools/msvc9_support.py
--- old/setuptools-11.3.1/setuptools/msvc9_support.py   2015-01-05 
18:59:01.000000000 +0100
+++ new/setuptools-12.0.3/setuptools/msvc9_support.py   2015-01-19 
00:48:58.000000000 +0100
@@ -1,5 +1,3 @@
-import sys
-
 try:
     import distutils.msvc9compiler
 except ImportError:
@@ -29,13 +27,15 @@
 def find_vcvarsall(version):
     Reg = distutils.msvc9compiler.Reg
     VC_BASE = r'Software\%sMicrosoft\DevDiv\VCForPython\%0.1f'
+    key = VC_BASE % ('', version)
     try:
         # Per-user installs register the compiler path here
-        productdir = Reg.get_value(VC_BASE % ('', version), "installdir")
+        productdir = Reg.get_value(key, "installdir")
     except KeyError:
         try:
             # All-user installs on a 64-bit system register here
-            productdir = Reg.get_value(VC_BASE % ('Wow6432Node\\', version), 
"installdir")
+            key = VC_BASE % ('Wow6432Node\\', version)
+            productdir = Reg.get_value(key, "installdir")
         except KeyError:
             productdir = None
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/setuptools-11.3.1/setuptools/sandbox.py 
new/setuptools-12.0.3/setuptools/sandbox.py
--- old/setuptools-11.3.1/setuptools/sandbox.py 2015-01-05 18:59:01.000000000 
+0100
+++ new/setuptools-12.0.3/setuptools/sandbox.py 2015-01-19 00:48:58.000000000 
+0100
@@ -92,6 +92,51 @@
         os.chdir(saved)
 
 
+class UnpickleableException(Exception):
+    """
+    An exception representing another Exception that could not be pickled.
+    """
+    @classmethod
+    def dump(cls, type, exc):
+        """
+        Always return a dumped (pickled) type and exc. If exc can't be pickled,
+        wrap it in UnpickleableException first.
+        """
+        try:
+            return pickle.dumps(type), pickle.dumps(exc)
+        except Exception:
+            return cls.dump(cls, cls(repr(exc)))
+
+
+class ExceptionSaver:
+    """
+    A Context Manager that will save an exception, serialized, and restore it
+    later.
+    """
+    def __enter__(self):
+        return self
+
+    def __exit__(self, type, exc, tb):
+        if not exc:
+            return
+
+        # dump the exception
+        self._saved = UnpickleableException.dump(type, exc)
+        self._tb = tb
+
+        # suppress the exception
+        return True
+
+    def resume(self):
+        "restore and re-raise any exception"
+
+        if '_saved' not in vars(self):
+            return
+
+        type, exc = map(pickle.loads, self._saved)
+        compat.reraise(type, exc, self._tb)
+
+
 @contextlib.contextmanager
 def save_modules():
     """
@@ -101,31 +146,20 @@
     outside the context.
     """
     saved = sys.modules.copy()
-    try:
-        try:
-            yield saved
-        except:
-            # dump any exception
-            class_, exc, tb = sys.exc_info()
-            saved_cls = pickle.dumps(class_)
-            saved_exc = pickle.dumps(exc)
-            raise
-        finally:
-            sys.modules.update(saved)
-            # remove any modules imported since
-            del_modules = (
-                mod_name for mod_name in sys.modules
-                if mod_name not in saved
-                # exclude any encodings modules. See #285
-                and not mod_name.startswith('encodings.')
-            )
-            _clear_modules(del_modules)
-    except:
-        # reload and re-raise any exception, using restored modules
-        class_, exc, tb = sys.exc_info()
-        new_cls = pickle.loads(saved_cls)
-        new_exc = pickle.loads(saved_exc)
-        compat.reraise(new_cls, new_exc, tb)
+    with ExceptionSaver() as saved_exc:
+        yield saved
+
+    sys.modules.update(saved)
+    # remove any modules imported since
+    del_modules = (
+        mod_name for mod_name in sys.modules
+        if mod_name not in saved
+        # exclude any encodings modules. See #285
+        and not mod_name.startswith('encodings.')
+    )
+    _clear_modules(del_modules)
+
+    saved_exc.resume()
 
 
 def _clear_modules(module_names):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/setuptools-11.3.1/setuptools/tests/contexts.py 
new/setuptools-12.0.3/setuptools/tests/contexts.py
--- old/setuptools-11.3.1/setuptools/tests/contexts.py  2015-01-05 
18:59:01.000000000 +0100
+++ new/setuptools-12.0.3/setuptools/tests/contexts.py  2015-01-19 
00:48:58.000000000 +0100
@@ -27,7 +27,7 @@
     to clear the values.
     """
     saved = dict(
-        (key, os.environ['key'])
+        (key, os.environ[key])
         for key in replacements
         if key in os.environ
     )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/setuptools-11.3.1/setuptools/tests/fixtures.py 
new/setuptools-12.0.3/setuptools/tests/fixtures.py
--- old/setuptools-11.3.1/setuptools/tests/fixtures.py  2015-01-05 
18:59:01.000000000 +0100
+++ new/setuptools-12.0.3/setuptools/tests/fixtures.py  2015-01-19 
00:48:58.000000000 +0100
@@ -1,4 +1,7 @@
-import mock
+try:
+    from unittest import mock
+except ImportError:
+    import mock
 import pytest
 
 from . import contexts
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/setuptools-11.3.1/setuptools/tests/py26compat.py 
new/setuptools-12.0.3/setuptools/tests/py26compat.py
--- old/setuptools-11.3.1/setuptools/tests/py26compat.py        2015-01-05 
18:59:01.000000000 +0100
+++ new/setuptools-12.0.3/setuptools/tests/py26compat.py        2015-01-19 
01:21:40.000000000 +0100
@@ -8,4 +8,7 @@
        """
        return contextlib.closing(tarfile.open(*args, **kwargs))
 
-tarfile_open = _tarfile_open_ex if sys.version_info < (2,7) else tarfile.open
+if sys.version_info[:2] < (2, 7) or (3, 0) <= sys.version_info[:2] < (3, 2):
+    tarfile_open = _tarfile_open_ex
+else:
+    tarfile_open = tarfile.open
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/setuptools-11.3.1/setuptools/tests/test_easy_install.py 
new/setuptools-12.0.3/setuptools/tests/test_easy_install.py
--- old/setuptools-11.3.1/setuptools/tests/test_easy_install.py 2015-01-05 
18:59:01.000000000 +0100
+++ new/setuptools-12.0.3/setuptools/tests/test_easy_install.py 2015-01-19 
02:14:42.000000000 +0100
@@ -1,4 +1,4 @@
-#! -*- coding: utf-8 -*-
+# -*- coding: utf-8 -*-
 
 """Easy install Tests
 """
@@ -15,20 +15,23 @@
 import itertools
 
 import pytest
-import mock
+try:
+    from unittest import mock
+except ImportError:
+    import mock
 
 from setuptools import sandbox
 from setuptools import compat
 from setuptools.compat import StringIO, BytesIO, urlparse
-from setuptools.sandbox import run_setup, SandboxViolation
+from setuptools.sandbox import run_setup
 from setuptools.command.easy_install import (
-    easy_install, fix_jython_executable, get_script_args, nt_quote_arg,
-    get_script_header, is_sh,
+    easy_install, fix_jython_executable, nt_quote_arg,
+    is_sh, ScriptWriter, CommandSpec,
 )
 from setuptools.command.easy_install import PthDistributions
 from setuptools.command import easy_install as easy_install_pkg
 from setuptools.dist import Distribution
-from pkg_resources import working_set, VersionConflict
+from pkg_resources import working_set
 from pkg_resources import Distribution as PRDistribution
 import setuptools.tests.server
 import pkg_resources
@@ -83,7 +86,7 @@
     def test_get_script_args(self):
         dist = FakeDist()
 
-        args = next(get_script_args(dist))
+        args = next(ScriptWriter.get_args(dist))
         name, script = itertools.islice(args, 2)
 
         assert script == WANTED
@@ -425,15 +428,22 @@
     )
     def test_get_script_header(self):
         expected = '#!%s\n' % nt_quote_arg(os.path.normpath(sys.executable))
-        assert get_script_header('#!/usr/local/bin/python') == expected
-        expected = '#!%s  -x\n' % 
nt_quote_arg(os.path.normpath(sys.executable))
-        assert get_script_header('#!/usr/bin/python -x') == expected
-        candidate = get_script_header('#!/usr/bin/python',
+        actual = ScriptWriter.get_script_header('#!/usr/local/bin/python')
+        assert actual == expected
+
+        expected = '#!%s -x\n' % nt_quote_arg(os.path.normpath(sys.executable))
+        actual = ScriptWriter.get_script_header('#!/usr/bin/python -x')
+        assert actual == expected
+
+        actual = ScriptWriter.get_script_header('#!/usr/bin/python',
             executable=self.non_ascii_exe)
-        assert candidate == '#!%s -x\n' % self.non_ascii_exe
-        candidate = get_script_header('#!/usr/bin/python',
-            executable=self.exe_with_spaces)
-        assert candidate == '#!"%s"\n' % self.exe_with_spaces
+        expected = '#!%s -x\n' % self.non_ascii_exe
+        assert actual == expected
+
+        actual = ScriptWriter.get_script_header('#!/usr/bin/python',
+            executable='"'+self.exe_with_spaces+'"')
+        expected = '#!"%s"\n' % self.exe_with_spaces
+        assert actual == expected
 
     @pytest.mark.xfail(
         compat.PY3 and os.environ.get("LC_CTYPE") in ("C", "POSIX"),
@@ -453,7 +463,8 @@
             f.write(header)
         exe = str(exe)
 
-        header = get_script_header('#!/usr/local/bin/python', executable=exe)
+        header = ScriptWriter.get_script_header('#!/usr/local/bin/python',
+            executable=exe)
         assert header == '#!/usr/bin/env %s\n' % exe
 
         expect_out = 'stdout' if sys.version_info < (2,7) else 'stderr'
@@ -461,15 +472,57 @@
         with contexts.quiet() as (stdout, stderr):
             # When options are included, generate a broken shebang line
             # with a warning emitted
-            candidate = get_script_header('#!/usr/bin/python -x',
+            candidate = ScriptWriter.get_script_header('#!/usr/bin/python -x',
                 executable=exe)
-            assert candidate == '#!%s  -x\n' % exe
+            assert candidate == '#!%s -x\n' % exe
             output = locals()[expect_out]
             assert 'Unable to adapt shebang line' in output.getvalue()
 
         with contexts.quiet() as (stdout, stderr):
-            candidate = get_script_header('#!/usr/bin/python',
+            candidate = ScriptWriter.get_script_header('#!/usr/bin/python',
                 executable=self.non_ascii_exe)
             assert candidate == '#!%s -x\n' % self.non_ascii_exe
             output = locals()[expect_out]
             assert 'Unable to adapt shebang line' in output.getvalue()
+
+
+class TestCommandSpec:
+    def test_custom_launch_command(self):
+        """
+        Show how a custom CommandSpec could be used to specify a #! executable
+        which takes parameters.
+        """
+        cmd = CommandSpec(['/usr/bin/env', 'python3'])
+        assert cmd.as_header() == '#!/usr/bin/env python3\n'
+
+    def test_from_param_for_CommandSpec_is_passthrough(self):
+        """
+        from_param should return an instance of a CommandSpec
+        """
+        cmd = CommandSpec(['python'])
+        cmd_new = CommandSpec.from_param(cmd)
+        assert cmd is cmd_new
+
+    def test_from_environment_with_spaces_in_executable(self):
+        with mock.patch('sys.executable', TestScriptHeader.exe_with_spaces):
+            cmd = CommandSpec.from_environment()
+        assert len(cmd) == 1
+        assert cmd.as_header().startswith('#!"')
+
+    def test_from_simple_string_uses_shlex(self):
+        """
+        In order to support `executable = /usr/bin/env my-python`, make sure
+        from_param invokes shlex on that input.
+        """
+        cmd = CommandSpec.from_param('/usr/bin/env my-python')
+        assert len(cmd) == 2
+        assert '"' not in cmd.as_header()
+
+    def test_sys_executable(self):
+        """
+        CommandSpec.from_string(sys.executable) should contain just that param.
+        """
+        writer = ScriptWriter.best()
+        cmd = writer.command_spec_class.from_string(sys.executable)
+        assert len(cmd) == 1
+        assert cmd[0] == sys.executable
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/setuptools-11.3.1/setuptools/tests/test_integration.py 
new/setuptools-12.0.3/setuptools/tests/test_integration.py
--- old/setuptools-11.3.1/setuptools/tests/test_integration.py  2015-01-05 
18:59:01.000000000 +0100
+++ new/setuptools-12.0.3/setuptools/tests/test_integration.py  2015-01-19 
00:48:58.000000000 +0100
@@ -12,6 +12,7 @@
 from setuptools.command.easy_install import easy_install
 from setuptools.command import easy_install as easy_install_pkg
 from setuptools.dist import Distribution
+from setuptools.compat import urlopen
 
 
 def setup_module(module):
@@ -24,6 +25,11 @@
         except ImportError:
             pass
 
+    try:
+        urlopen('https://pypi.python.org/pypi')
+    except Exception as exc:
+        pytest.skip(reason=str(exc))
+
 
 @pytest.fixture
 def install_context(request, tmpdir, monkeypatch):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/setuptools-11.3.1/setuptools/tests/test_msvc9compiler.py 
new/setuptools-12.0.3/setuptools/tests/test_msvc9compiler.py
--- old/setuptools-11.3.1/setuptools/tests/test_msvc9compiler.py        
2015-01-05 18:59:01.000000000 +0100
+++ new/setuptools-12.0.3/setuptools/tests/test_msvc9compiler.py        
2015-01-19 00:48:58.000000000 +0100
@@ -7,7 +7,10 @@
 import distutils.errors
 
 import pytest
-import mock
+try:
+    from unittest import mock
+except ImportError:
+    import mock
 
 from . import contexts
 
@@ -110,7 +113,8 @@
         Ensure user's settings are preferred.
         """
         result = distutils.msvc9compiler.find_vcvarsall(9.0)
-        assert user_preferred_setting == result
+        expected = os.path.join(user_preferred_setting, 'vcvarsall.bat')
+        assert expected == result
 
     @pytest.yield_fixture
     def local_machine_setting(self):
@@ -131,13 +135,14 @@
         Ensure machine setting is honored if user settings are not present.
         """
         result = distutils.msvc9compiler.find_vcvarsall(9.0)
-        assert local_machine_setting == result
+        expected = os.path.join(local_machine_setting, 'vcvarsall.bat')
+        assert expected == result
 
     @pytest.yield_fixture
     def x64_preferred_setting(self):
         """
         Set up environment with 64-bit and 32-bit system settings configured
-        and yield the 64-bit location.
+        and yield the canonical location.
         """
         with self.mock_install_dir() as x32_dir:
             with self.mock_install_dir() as x64_dir:
@@ -150,14 +155,15 @@
                     },
                 )
                 with reg:
-                    yield x64_dir
+                    yield x32_dir
 
     def test_ensure_64_bit_preferred(self, x64_preferred_setting):
         """
         Ensure 64-bit system key is preferred.
         """
         result = distutils.msvc9compiler.find_vcvarsall(9.0)
-        assert x64_preferred_setting == result
+        expected = os.path.join(x64_preferred_setting, 'vcvarsall.bat')
+        assert expected == result
 
     @staticmethod
     @contextlib.contextmanager
@@ -170,4 +176,4 @@
             vcvarsall = os.path.join(result, 'vcvarsall.bat')
             with open(vcvarsall, 'w'):
                 pass
-            yield
+            yield result
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/setuptools-11.3.1/setuptools/tests/test_sandbox.py 
new/setuptools-12.0.3/setuptools/tests/test_sandbox.py
--- old/setuptools-11.3.1/setuptools/tests/test_sandbox.py      2015-01-05 
18:59:01.000000000 +0100
+++ new/setuptools-12.0.3/setuptools/tests/test_sandbox.py      2015-01-19 
00:48:58.000000000 +0100
@@ -7,7 +7,7 @@
 
 import pkg_resources
 import setuptools.sandbox
-from setuptools.sandbox import DirectorySandbox, SandboxViolation
+from setuptools.sandbox import DirectorySandbox
 
 
 class TestSandbox:
@@ -54,3 +54,49 @@
         with setup_py.open('wb') as stream:
             stream.write(b'"degenerate script"\r\n')
         setuptools.sandbox._execfile(str(setup_py), globals())
+
+
+class TestExceptionSaver:
+    def test_exception_trapped(self):
+        with setuptools.sandbox.ExceptionSaver():
+            raise ValueError("details")
+
+    def test_exception_resumed(self):
+        with setuptools.sandbox.ExceptionSaver() as saved_exc:
+            raise ValueError("details")
+
+        with pytest.raises(ValueError) as caught:
+            saved_exc.resume()
+
+        assert isinstance(caught.value, ValueError)
+        assert str(caught.value) == 'details'
+
+    def test_exception_reconstructed(self):
+        orig_exc = ValueError("details")
+
+        with setuptools.sandbox.ExceptionSaver() as saved_exc:
+            raise orig_exc
+
+        with pytest.raises(ValueError) as caught:
+            saved_exc.resume()
+
+        assert isinstance(caught.value, ValueError)
+        assert caught.value is not orig_exc
+
+    def test_no_exception_passes_quietly(self):
+        with setuptools.sandbox.ExceptionSaver() as saved_exc:
+            pass
+
+        saved_exc.resume()
+
+    def test_unpickleable_exception(self):
+        class CantPickleThis(Exception):
+            "This Exception is unpickleable because it's not in globals"
+
+        with setuptools.sandbox.ExceptionSaver() as saved_exc:
+            raise CantPickleThis('detail')
+
+        with pytest.raises(setuptools.sandbox.UnpickleableException) as caught:
+            saved_exc.resume()
+
+        assert str(caught.value) == "CantPickleThis('detail',)"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/setuptools-11.3.1/setuptools/version.py 
new/setuptools-12.0.3/setuptools/version.py
--- old/setuptools-11.3.1/setuptools/version.py 2015-01-06 16:11:49.000000000 
+0100
+++ new/setuptools-12.0.3/setuptools/version.py 2015-01-19 02:43:32.000000000 
+0100
@@ -1 +1 @@
-__version__ = '11.3.1'
+__version__ = '12.0.3'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/setuptools-11.3.1/setuptools.egg-info/PKG-INFO 
new/setuptools-12.0.3/setuptools.egg-info/PKG-INFO
--- old/setuptools-11.3.1/setuptools.egg-info/PKG-INFO  2015-01-06 
16:11:56.000000000 +0100
+++ new/setuptools-12.0.3/setuptools.egg-info/PKG-INFO  2015-01-19 
02:48:34.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: setuptools
-Version: 11.3.1
+Version: 12.0.3
 Summary: Easily download, build, install, upgrade, and uninstall Python 
packages
 Home-page: https://bitbucket.org/pypa/setuptools
 Author: Python Packaging Authority

-- 
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to