[Distutils] setup.py install using pip

Ronny Pfannschmidt opensource at ronnypfannschmidt.de
Fri Dec 4 02:55:14 EST 2015

But it still needs a change in command
A direct switch to a real pip command comes with a free implementation and zero additional features to maintain in setuptools

Am 3. Dezember 2015 23:01:21 MEZ, schrieb Erik Bray <erik.m.bray at gmail.com>:
>On Thu, Dec 3, 2015 at 3:37 PM, Ronny Pfannschmidt
><opensource at ronnypfannschmidt.de> wrote:
>> Lets avoid getting setuptools even more complex in that way
>It's not deeply complex--it's just bypassing the normal behavior of
>using easy_install.  In my example code I subclassed
>the existing command, but an easier approach would be to build it into
>The way the 'install' command works in setuptools is to hand
>installation off to the easy_install command unless
>--single-version-externally-managed is specified (as well as
>--record).  Otherwise it hands installation off to the default
>base 'install' command of distutils.
>This proposal just adds a third option for what actual installer the
>'install' command should
>use.  But it's opt-in instead of forced on any package by default (as
>easy_install is forced on us by setuptools).
>> Putting pip-ish-ness on top of easy install is a maintenance horror
>and I don't think setuptools does has enough consistent developer
>resources to handle something like that
>It doesn't put anything "on top of" easy_install; it ignores
>> Instead let's just give options to destroy the normal install command
>from setup.py so projects can phase out easy install forcefully making
>downstream require patches or pip usage
>That's the goal, yes.  This is just offering a transitional tool.
>> Am 3. Dezember 2015 21:06:06 MEZ, schrieb Erik Bray
><erik.m.bray at gmail.com>:
>>>Hi all,
>>>I've been on vacation for a bit in general, and on vacation from this
>>>mailing list even longer.  I'm not entirely caught up yet on the
>>>latest developments so apologies if something like this is entirely
>>>moot by now.
>>>But I have seen some discussions here and in other lists related to
>>>using pip for all installations, and phasing out the old distutils
>>>`./setup.py install` (eg. [1]).  This is not a new discussion, and
>>>there are many related discussions, for example, about changing
>>>setuptools not to default to egg installs anymore (see [2]).
>>>I'm definitely all for this in general.  Nowadays whenever I install
>>>package from source I run `pip install .`  But of course there are a
>>>lot of existing tools, not to mention folk wisdom, assuming
>>>`./setup.py install`.  We also don't want to change the long-existing
>>>behavior in setuptools.
>>>I have a modest proposal for a small addition to setuptools that
>>>be helpful in a transition away from using setuptools+distutils for
>>>installation.  This would be to add a `--pip` flag to setuptools'
>>>install command (or possibly straight in distutils too, but might as
>>>well start with setuptools).
>>>Therefore, running
>>>$ ./setup.py install --pip
>>>would be equivalent to running
>>>$ pip install .
>>>By extension, running
>>>$ ./setup.py install --pip --arg1 --arg2=foo
>>>would be equivalent to
>>>$ pip install --install-option="--arg1" --install-option="--arg2=foo"
>>>and so on.
>>>By making `--pip` opt-in, it does not automatically break backward
>>>compatibility for users expecting `./setup.py install` to use
>>>easy_install.  However, individual users may opt into it globally by
>>>pip = True
>>>to their .pydistutils.cfg.  Similarly, package authors who are
>>>confident that none of their users are ever going to care about egg
>>>installs (e.g. me) can add the same to their project's setup.cfg.
>>>Does something like this have any merit?  I hacked together a
>>>prototype which follows the sig line.  It's just a proof of concept,
>>>but seems to work in the most basic cases.  I'd like to add it to my
>>>own projects too, but would appreciate some peer review.
>>>$ cat pipinstall.py
>>>from distutils.errors import DistutilsArgError
>>>from setuptools.command.install import install as SetuptoolsInstall
>>>class PipInstall(SetuptoolsInstall):
>>>    command_name = 'install'
>>>    user_options = SetuptoolsInstall.user_options + [
>>>        ('pip', None, 'install using pip; ignored when also using '
>>>                      '--single-version-externally-managed')
>>>    ]
>>>    boolean_options = SetuptoolsInstall.boolean_options + ['pip']
>>>    def initialize_options(self):
>>>        SetuptoolsInstall.initialize_options(self)
>>>        self.pip = False
>>>    def finalize_options(self):
>>>        SetuptoolsInstall.finalize_options(self)
>>>        if self.single_version_externally_managed:
>>>            self.pip = False
>>>        if self.pip:
>>>            try:
>>>                import pip
>>>            except ImportError:
>>>                raise DistutilsArgError(
>>>                  'pip must be installed in order to install with the
>>>                    '--pip option')
>>>    def run(self):
>>>        if self.pip:
>>>            import pip
>>>            opts = (['install', '--ignore-installed'] +
>>>                    ['--install-option="{0}"'.format(opt)
>>>                     for opt in self._get_command_line_opts()])
>>>            pip.main(opts + ['.'])
>>>        else:
>>>            SetuptoolsInstall.run(self)
>>>    def _get_command_line_opts(self):
>>>        # Generate a mapping from the attribute name associated with
>>># command-line option to the name of the command-line option
>>>        # an = if the option takes an argument)
>>>      attr_to_opt = dict((opt[0].rstrip('=').replace('-', '_'),
>>>                           for opt in self.user_options)
>>>  opt_dict =
>>>        opts = []
>>>        for attr, value in opt_dict.items():
>>>            if value[0] != 'command line' or attr == 'pip':
>>>         # Only look at options passed in on the command line
>>>                # the pip option itself)
>>>                continue
>>>            opt = attr_to_opt[attr]
>>>            if opt in self.boolean_options:
>>>                opts.append('--' + opt)
>>>            else:
>>>                opts.append('--{0}{1}'.format(opt, value[1]))
>>>        return opts
>>>    @staticmethod
>>>    def _called_from_setup(run_frame):
>>>        # A hack to work around a setuptools hack
>>>        return SetuptoolsInstall._called_from_setup(run_frame.f_back)
>>>Distutils-SIG maillist  -  Distutils-SIG at python.org
>> MFG Ronny

MFG Ronny

More information about the Distutils-SIG mailing list