Skip to content

Commit

Permalink
Write a temporary setup.cfg to override any system distutils configur…
Browse files Browse the repository at this point in the history
…ation (#18)

* Write a temporary setup.cfg to override any system distutils configuration

Previously, shiv could not install packages that did not provide wheels
using Homebrew's Pythons, because `--target` is incompatible with
Homebrew's `distutils.cfg`. We can work around that by creating a
`setup.cfg` in the same directory we run `pip install` containing:

```ini
[install]
prefix=
```

Fixes #16.

* Restore the previous directory after installing

* Move temporary setup.cfg to clean_pip_env()
  • Loading branch information
rouge8 authored and lorencarvalho committed May 5, 2018
1 parent 29fb7c3 commit 33cf133
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 8 deletions.
1 change: 1 addition & 0 deletions src/shiv/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@
("-d", "--download"): "Shiv needs to actually perform an install, not merely a download.",
("--user", "--root", "--prefix"): "Which conflicts with Shiv's internal use of '--target'.",
}
SETUP_CFG_NO_PREFIX = "[install]\nprefix="
32 changes: 24 additions & 8 deletions src/shiv/pip.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
import subprocess
import sys

from pathlib import Path
from tempfile import TemporaryDirectory
from typing import Generator, List

from .constants import PIP_REQUIRE_VIRTUALENV, PIP_INSTALL_ERROR
from .constants import PIP_REQUIRE_VIRTUALENV, PIP_INSTALL_ERROR, SETUP_CFG_NO_PREFIX


@contextlib.contextmanager
Expand All @@ -16,13 +18,27 @@ def clean_pip_env() -> Generator[None, None, None]:
"""
require_venv = os.environ.pop(PIP_REQUIRE_VIRTUALENV, None)

try:
yield

finally:
if require_venv is not None:
os.environ[PIP_REQUIRE_VIRTUALENV] = require_venv
cwd = Path.cwd()

with TemporaryDirectory() as working_path:
# distutils doesn't support using --target if there's a config file
# specifying --prefix. Homebrew's Pythons include a distutils.cfg that
# breaks `pip install --target` with any non-wheel packages. We can
# work around that by creating a setup.cfg specifying an empty prefix
# in the directory we run `pip install` from.
with Path(working_path, "setup.cfg").open("w") as f:
f.write(SETUP_CFG_NO_PREFIX)
os.chdir(working_path)

try:
yield

finally:
if require_venv is not None:
os.environ[PIP_REQUIRE_VIRTUALENV] = require_venv

# return to the previous working directory
os.chdir(cwd)


def install(interpreter_path: str, args: List[str]) -> None:
Expand Down
26 changes: 26 additions & 0 deletions test/test_pip.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import os

from pathlib import Path

from shiv.constants import PIP_REQUIRE_VIRTUALENV
from shiv.constants import SETUP_CFG_NO_PREFIX
from shiv.pip import clean_pip_env


def test_clean_pip_env(monkeypatch):
before_env_var = 'foo'
monkeypatch.setenv(PIP_REQUIRE_VIRTUALENV, before_env_var)

before_cwd = Path.cwd()

with clean_pip_env():
assert PIP_REQUIRE_VIRTUALENV not in os.environ

cwd = Path.cwd()
assert cwd != before_cwd

with cwd.joinpath("setup.cfg").open() as f:
assert f.read() == SETUP_CFG_NO_PREFIX

assert os.environ.get(PIP_REQUIRE_VIRTUALENV) == before_env_var
assert Path.cwd() == before_cwd

0 comments on commit 33cf133

Please sign in to comment.