question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

--build-dir is not respected when installing from an sdist without a req

See original GitHub issue

Reproduction steps

$ python3 -m venv env
$ env/bin/pip --version
pip 9.0.1 from .../env/lib/python3.5/site-packages (python 3.5)
$ mkdir mydist
$ cat > mydist/setup.py
import os
import sys
from setuptools import setup
assert "egg_info" in sys.argv or "my-build-dir" in os.getcwd()
setup(name="example")
$ tar czf mydist.tar.gz mydist/*
$ env/bin/pip install -v mydist.tar.gz 
Processing ./mydist.tar.gz
  Running setup.py (path:/tmp/pip-ynhyamwl-build/setup.py) egg_info for package from file:///home/benjamin/dev/repos/repo/mydist.tar.gz
    Running command python setup.py egg_info
    running egg_info
    creating pip-egg-info/example.egg-info
    writing top-level names to pip-egg-info/example.egg-info/top_level.txt
    writing dependency_links to pip-egg-info/example.egg-info/dependency_links.txt
    writing pip-egg-info/example.egg-info/PKG-INFO
    writing manifest file 'pip-egg-info/example.egg-info/SOURCES.txt'
    warning: manifest_maker: standard file '-c' not found

    reading manifest file 'pip-egg-info/example.egg-info/SOURCES.txt'
    writing manifest file 'pip-egg-info/example.egg-info/SOURCES.txt'
  Source in /tmp/pip-ynhyamwl-build has version 0.0.0, which satisfies requirement example==0.0.0 from file:///home/benjamin/dev/repos/repo/mydist.tar.gz
Installing collected packages: example
  Running setup.py install for example ...     Running command /home/benjamin/dev/repos/repo/env/bin/python3 -u -c "import setuptools, tokenize;__file__='/tmp/pip-ynhyamwl-build/setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --record /tmp/pip-mpcj19ev-record/install-record.txt --single-version-externally-managed --compile --install-headers /home/benjamin/dev/repos/repo/env/include/site/python3.5/example
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "/tmp/pip-ynhyamwl-build/setup.py", line 4, in <module>
        assert "egg_info" in sys.argv or "my-build-dir" in os.getcwd()
    AssertionError
error
Cleaning up...
  Removing source in /tmp/pip-ynhyamwl-build
Command "/home/benjamin/dev/repos/repo/env/bin/python3 -u -c "import setuptools, tokenize;__file__='/tmp/pip-ynhyamwl-build/setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --record /tmp/pip-mpcj19ev-record/install-record.txt --single-version-externally-managed --compile --install-headers /home/benjamin/dev/repos/repo/env/include/site/python3.5/example" failed with error code 1 in /tmp/pip-ynhyamwl-build/
Exception information:
Traceback (most recent call last):
  File "/home/benjamin/dev/repos/repo/env/lib/python3.5/site-packages/pip/basecommand.py", line 215, in main
    status = self.run(options, args)
  File "/home/benjamin/dev/repos/repo/env/lib/python3.5/site-packages/pip/commands/install.py", line 342, in run
    prefix=options.prefix_path,
  File "/home/benjamin/dev/repos/repo/env/lib/python3.5/site-packages/pip/req/req_set.py", line 784, in install
    **kwargs
  File "/home/benjamin/dev/repos/repo/env/lib/python3.5/site-packages/pip/req/req_install.py", line 878, in install
    spinner=spinner,
  File "/home/benjamin/dev/repos/repo/env/lib/python3.5/site-packages/pip/utils/__init__.py", line 707, in call_subprocess
    % (command_desc, proc.returncode, cwd))
pip.exceptions.InstallationError: Command "/home/benjamin/dev/repos/repo/env/bin/python3 -u -c "import setuptools, tokenize;__file__='/tmp/pip-ynhyamwl-build/setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install

Analysis

This bug only happens when a “req” is not given on the command line. (Indeed, it’s possible work around the bug by passing a file:// URL with a #egg=mydist fragment.) When a “req” is not given, pip determines the distribution name by running setup.py egg_info and parsing the distribution name from the resulting metadata. egg_info is always run in a temporary directory selected by pip (see InstallRequirement.build_location). The bug is that this directory is then used for the actual build. The method InstallRequirement._correct_build_location is apparently supposed to address this very case by setting the build directory back to the user-specified one. However, it is always noop because it’s early exit condition self.source_dir is not None is always true. (One can almost prove this because the singular caller of _correct_build_location, run_egg_info asserts that self.source_dir is not None.)

Would it be possible to use the user-specified --build-dir to run egg_info in and clean out the directory before running the real build? That would fix this bug, make the behavior more consistent, and likely simplify InstallRequirement’s code.

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Reactions:4
  • Comments:10 (8 by maintainers)

github_iconTop GitHub Comments

5reactions
pvcommented, Jul 24, 2017

I’d like to note that another use case for --build in addition to reproducible builds, is the use of compiler build caches, ccache in particular. In practice (see https://github.com/scipy/scipy/pull/7647, https://github.com/spacetelescope/asv/issues/201, https://github.com/spacetelescope/asv/pull/203) the fact that pip builds projects in a directory with a random name often prevents ccache from working properly.

One particular use case here is asv, which needs to rebuild and reinstall Python projects very many times, and significantly benefits from ccache. (For instance, with proper caching Scipy build goes from 10min to <1min.) However, we have to jump through some extra hoops in the build automation because --build doesn’t work as advertised.

I wasn’t aware that --build actually works with the (pretty obscure) file://...#egg=foo syntax, but that looks like a somewhat unreliable workaround…

Another use case for ccache is in continuous integration (e.g. travis-CI). Here, one can sometimes avoid use of pip, but it’s not so easy to find out the reason why ccache doesn’t work properly when using pip.

1reaction
benjaminpcommented, Apr 1, 2017

A classic example is this numpy code generator that writes generator’s __file__ (thus, including the build directory) into its output artifacts. C extensions also generally leak their build directory into the debugging info.

I decided it was easier to systematically bandaid the problem by using a constant --build-dir rather than whack-a-mole fixing issues in individual packages.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Running sDist to build a package and install creates empty ...
when running python setup.py sdist, the result creates a dist folder with a zip file (I am on windows). when opening this file...
Read more >
pip install — pip 10.0.0.dev0 documentation
For non-editable installs, the project is built locally in a temp dir and then installed normally. Note that if a satisfactory version of...
Read more >
A tour on Python Packaging - Alone Djangonaut
By pip install ing the package, these requirements will not be honored. These are just for development cases. The official docs say: Whereas ......
Read more >
pip install — pip 8.1.1 documentation
When no wheels are found for an sdist, pip will attempt to build a wheel automatically and insert it into the wheel cache....
Read more >
Changelog - pip documentation v22.3.1
Deprecate installation with 'setup.py install' when no-binary is enabled for source ... Allow using a pre-release version to satisfy a build requirement.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found