New submission from Igor Filatov:

ensurepip runs pip with a function that discards the result code that pip 
produces:

    def _run_pip(args, additional_paths=None):
        # ...
        pip.main(args)

pip.main() is designed not to raise command exceptions. Instead it returns exit 
codes which are to be passed to sys.exit(). Since ensurepip does not process 
the return value of pip.main() in any way, python -m ensurepip always exits 
with 0 on such exceptions (even though there's a stack trace, printing of which 
is handled by pip). EC should be 0 only in case of success.

This is an issue in venv because it runs ensurepip in a subprocess and cannot 
detect a failure:

    def _setup_pip(self, context):
        # ...
        cmd = [context.env_exe, '-Im', 'ensurepip', '--upgrade',
                                                    '--default-pip']
        subprocess.check_output(cmd, stderr=subprocess.STDOUT)

And this leads to broken venvs in some cases. The easiest way to reproduce:

    $ mkdir venv-test
    $ cd venv-test/
    $ echo garbage > setup.cfg
    $ python3 -m venv broken
    $ broken/bin/pip
    bash: broken/bin/pip: No such file or directory

There are no errors until you need pip. The culprit is this:

    $ broken/bin/python -Im ensurepip --upgrade --default-pip
    Ignoring indexes: https://pypi.python.org/simple
    Collecting setuptools
    Collecting pip
    Collecting pkg_resources
    Installing collected packages: setuptools, pip, pkg-resources
    Exception:
    Traceback (most recent call last):
      File 
"/tmp/tmpgjpdbf_e/pip-8.1.1-py2.py3-none-any.whl/pip/basecommand.py", line 209, 
in main
        status = self.run(options, args)
      File 
"/tmp/tmpgjpdbf_e/pip-8.1.1-py2.py3-none-any.whl/pip/commands/install.py", line 
335, in run
        prefix=options.prefix_path,
      File 
"/tmp/tmpgjpdbf_e/pip-8.1.1-py2.py3-none-any.whl/pip/req/req_set.py", line 732, 
in install
        **kwargs
      File 
"/tmp/tmpgjpdbf_e/pip-8.1.1-py2.py3-none-any.whl/pip/req/req_install.py", line 
837, in install
        self.move_wheel_files(self.source_dir, root=root, prefix=prefix)
      File 
"/tmp/tmpgjpdbf_e/pip-8.1.1-py2.py3-none-any.whl/pip/req/req_install.py", line 
1039, in move_wheel_files
        isolated=self.isolated,
      File "/tmp/tmpgjpdbf_e/pip-8.1.1-py2.py3-none-any.whl/pip/wheel.py", line 
247, in move_wheel_files
        prefix=prefix,
      File "/tmp/tmpgjpdbf_e/pip-8.1.1-py2.py3-none-any.whl/pip/locations.py", 
line 141, in distutils_scheme
        d.parse_config_files()
      File "/usr/lib/python3.5/distutils/dist.py", line 395, in 
parse_config_files
        parser.read(filename)
      File "/usr/lib/python3.5/configparser.py", line 696, in read
        self._read(fp, filename)
      File "/usr/lib/python3.5/configparser.py", line 1077, in _read
        raise MissingSectionHeaderError(fpname, lineno, line)
    configparser.MissingSectionHeaderError: File contains no section headers.
    file: 'setup.cfg', line: 1
    'garbage\n'

But any other exception during pip any_command would've had the same effect. 
This is hard to diagnose because no output is produced by subprocess due to the 
exception. 

ensurepip should propagate the code returned by pip and pass it to sys.exit(). 
Alternatively ensurepip can have it's own EC for cases when pip.main(args) != 0.

----------
components: Library (Lib)
messages: 301367
nosy: Igor Filatov
priority: normal
severity: normal
status: open
title: ensurepip discards pip's return code which leads to broken venvs
type: behavior
versions: Python 3.4, Python 3.5, Python 3.6, Python 3.7

_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue31351>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to